From 923e41c0291a0574919be69dc9368c403aacdc20 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 28 Aug 2023 16:56:59 +0200 Subject: [PATCH 001/267] MathNode: tellFailure and process the next message in the queue in case we are the last consumer --- .../rule/engine/math/TbMathNode.java | 15 ++++-- .../rule/engine/math/TbMathNodeTest.java | 54 +++++++++++++++++++ 2 files changed, 65 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index 5a0c717445..a2b809037b 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -154,10 +154,17 @@ public class TbMathNode implements TbNode { tryProcessQueue(lockAndQueue); } }, ctx.getDbCallbackExecutor()); - } catch (Throwable e) { + } catch (Throwable t) { semaphore.release(); - log.warn("[{}] Failed to process message: {}", lockAndQueue.getEntityId(), tbMsgTbContext == null ? null : tbMsgTbContext.getMsg(), e); - throw e; + if (tbMsgTbContext == null) { // if no message polled, the loop become infinite, will throw exception + log.error("[{}] Failed to process TbMsgTbContext queue", lockAndQueue.getEntityId(), t); + throw t; + } + TbMsg msg = tbMsgTbContext.getMsg(); + TbContext ctx = tbMsgTbContext.getCtx(); + log.warn("[{}] Failed to process message: {}", lockAndQueue.getEntityId(), msg, t); + ctx.tellFailure(msg, t); // you are not allowed to throw here, because queue will remain unprocessed + continue; // We are probably the last who process the queue. We have to continue poll until get successful callback or queue is empty } break; //submitted async exact one task. next poll will try on callback } @@ -364,7 +371,7 @@ public class TbMathNode implements TbNode { return function.apply(arg1.getValue(), arg2.getValue()); } - private ListenableFuture resolveArguments(TbContext ctx, TbMsg msg, Optional msgBodyOpt, TbMathArgument arg) { + ListenableFuture resolveArguments(TbContext ctx, TbMsg msg, Optional msgBodyOpt, TbMathArgument arg) { switch (arg.getType()) { case CONSTANT: return Futures.immediateFuture(TbMathArgumentValue.constant(arg)); diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index 50424a1521..4a5ec8b209 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -64,6 +64,7 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -577,6 +578,59 @@ public class TbMathNodeTest { verify(ctx, never()).tellFailure(any(), any()); } + @Test + public void testExp4j_concurrentBySingleOriginator_processMsgAsyncException() { + TbMathNode node = spy(initNodeWithCustomFunction("2a+3b", + new TbMathResult(TbMathArgumentType.MESSAGE_BODY, "result", 2, false, false, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b") + )); + + willThrow(new RuntimeException("Message body has no 'delta'")).given(node).resolveArguments(any(), any(), any(), any()); + + EntityId originatorSlow = DeviceId.fromString("7f01170d-6bba-419c-b95c-2b4c3ba32f30"); + CountDownLatch slowProcessingLatch = new CountDownLatch(1); + + List slowMsgList = IntStream.range(0, 5) + .mapToObj(x -> TbMsg.newMsg("TEST", originatorSlow, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString())) + .collect(Collectors.toList()); + + assertThat(slowMsgList.size()).as("slow msgs >= rule-dispatcher pool size").isGreaterThanOrEqualTo(RULE_DISPATCHER_POOL_SIZE); + + log.debug("rule-dispatcher [{}], db-callback [{}], slowMsg [{}]", RULE_DISPATCHER_POOL_SIZE, DB_CALLBACK_POOL_SIZE, slowMsgList.size()); + + willAnswer(invocation -> { + TbMsg msg = invocation.getArgument(1); + if (slowProcessingLatch.getCount() > 0) { + log.debug("Await on slowProcessingLatch before processMsgAsync"); + try { + assertThat(slowProcessingLatch.await(30, TimeUnit.SECONDS)).as("await on slowProcessingLatch").isTrue(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + log.debug("\uD83D\uDC0C processMsgAsync with exception [{}][{}]", msg.getOriginator(), msg); + return invocation.callRealMethod(); + }).given(node).processMsgAsync(eq(ctx), argThat(slowMsgList::contains)); + + willAnswer(invocation -> { + TbMsg msg = invocation.getArgument(1); + log.debug("submit slow originator onMsg [{}][{}]", msg.getOriginator(), msg); + return invocation.callRealMethod(); + }).given(node).onMsg(eq(ctx), argThat(slowMsgList::contains)); + + // submit slow msg may block all rule engine dispatcher threads + slowMsgList.forEach(msg -> ruleEngineDispatcherExecutor.executeAsync(() -> node.onMsg(ctx, msg))); + // wait until dispatcher threads started with all slowMsg + verify(node, new Timeout(TimeUnit.SECONDS.toMillis(5), times(slowMsgList.size()))).onMsg(eq(ctx), argThat(slowMsgList::contains)); + + slowProcessingLatch.countDown(); + + verify(ctx, new Timeout(TimeUnit.SECONDS.toMillis(5), times(slowMsgList.size()))).tellFailure(any(), any()); + verify(ctx, never()).tellSuccess(any()); + + } + static class RuleDispatcherExecutor extends AbstractListeningExecutor { @Override protected int getThreadPollSize() { From b82a5381e3ad3082e960b100f4825af87d60072d Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 28 Aug 2023 18:00:42 +0200 Subject: [PATCH 002/267] MathNodeTest: assertThrown replaced with tellFailure verification --- .../rule/engine/math/TbMathNodeTest.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index 4a5ec8b209..e1d2c5327d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -57,7 +57,6 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyDouble; import static org.mockito.ArgumentMatchers.anyString; @@ -490,10 +489,11 @@ public class TbMathNodeTest { new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "TestKey") ); TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 10).toString()); - Throwable thrown = assertThrows(RuntimeException.class, () -> { - node.onMsg(ctx, msg); - }); - Assert.assertNotNull(thrown.getMessage()); + node.onMsg(ctx, msg); + + ArgumentCaptor tCaptor = ArgumentCaptor.forClass(Throwable.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellFailure(eq(msg), tCaptor.capture()); + Assert.assertNotNull(tCaptor.getValue().getMessage()); } @Test @@ -504,10 +504,11 @@ public class TbMathNodeTest { ); TbMsg msg = TbMsg.newMsg("TEST", originator, new TbMsgMetaData(), "[]"); - Throwable thrown = assertThrows(RuntimeException.class, () -> { - node.onMsg(ctx, msg); - }); - Assert.assertNotNull(thrown.getMessage()); + node.onMsg(ctx, msg); + + ArgumentCaptor tCaptor = ArgumentCaptor.forClass(Throwable.class); + Mockito.verify(ctx, Mockito.timeout(5000)).tellFailure(eq(msg), tCaptor.capture()); + Assert.assertNotNull(tCaptor.getValue().getMessage()); } @Test From cfe79cc4458fd758210362338d7c407d4510ba6a Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 28 Aug 2023 19:12:33 +0200 Subject: [PATCH 003/267] AbstractScriptInvokeService: tenantId added to the log on script invocation blocked --- .../thingsboard/script/api/AbstractScriptInvokeService.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java index ac196a8edd..23274e863d 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java @@ -150,7 +150,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService } apiUsageReportClient.ifPresent(client -> client.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1)); pushedMsgs.incrementAndGet(); - log.trace("InvokeScript uuid {} with timeout {}ms", scriptId, getMaxInvokeRequestsTimeout()); + log.trace("[{}] InvokeScript uuid {} with timeout {}ms", tenantId, scriptId, getMaxInvokeRequestsTimeout()); var task = doInvokeFunction(scriptId, args); var resultFuture = Futures.transformAsync(task.getResultFuture(), output -> { @@ -167,7 +167,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService } else { String message = "Script invocation is blocked due to maximum error count " + getMaxErrors() + ", scriptId " + scriptId + "!"; - log.warn(message); + log.warn("[{}] " + message, tenantId); return error(message); } } else { From 8a6484203972f2c6b70021fb896680fbe5dda95e Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Wed, 30 Aug 2023 10:44:39 +0300 Subject: [PATCH 004/267] Add missing sleep, fix wrong timeout expiry check --- .../server/service/state/DefaultDeviceStateService.java | 2 +- .../server/service/state/DefaultDeviceStateServiceTest.java | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) 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 cdc5afe361..f9afb5b2e5 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 @@ -486,7 +486,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService Date: Wed, 30 Aug 2023 14:03:43 +0300 Subject: [PATCH 005/267] Add missing sleep in `decreaseInactivityForInactiveDeviceTest()` --- .../server/service/state/DefaultDeviceStateServiceTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index c0690c56e1..ceb98480c1 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -330,6 +330,7 @@ public class DefaultDeviceStateServiceTest { Mockito.reset(telemetrySubscriptionService); long newTimeout = 1; + Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); From 168d0980f0a4568a3b9f952436e535c1b22c75e6 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Wed, 30 Aug 2023 23:24:13 +0200 Subject: [PATCH 006/267] TbMathNode: test added concurrentBySingleOriginator_SingleMsg_manyNodesWithDifferentOutput --- .../rule/engine/math/TbMathNodeTest.java | 72 +++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index e1d2c5327d..c9659bad9f 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -17,6 +17,8 @@ package org.thingsboard.rule.engine.math; import com.google.common.util.concurrent.Futures; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.tuple.Triple; +import org.assertj.core.api.SoftAssertions; import org.junit.Assert; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; @@ -63,10 +65,13 @@ import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willAnswer; +import static org.mockito.BDDMockito.willReturn; import static org.mockito.BDDMockito.willThrow; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -122,7 +127,15 @@ public class TbMathNodeTest { return initNode(TbRuleNodeMathFunctionType.CUSTOM, expression, result, arguments); } + private TbMathNode initNodeWithCustomFunction(TbContext ctx, String expression, TbMathResult result, TbMathArgument... arguments) { + return initNode(ctx, TbRuleNodeMathFunctionType.CUSTOM, expression, result, arguments); + } + private TbMathNode initNode(TbRuleNodeMathFunctionType operation, String expression, TbMathResult result, TbMathArgument... arguments) { + return initNode(this.ctx, operation, expression, result, arguments); + } + + private TbMathNode initNode(TbContext ctx, TbRuleNodeMathFunctionType operation, String expression, TbMathResult result, TbMathArgument... arguments) { try { TbMathNodeConfiguration configuration = new TbMathNodeConfiguration(); configuration.setOperation(operation); @@ -632,6 +645,65 @@ public class TbMathNodeTest { } + @Test + public void testExp4j_concurrentBySingleOriginator_SingleMsg_manyNodesWithDifferentOutput() { + assertThat(RULE_DISPATCHER_POOL_SIZE).as("dispatcher pool size have to be > 1").isGreaterThan(1); + CountDownLatch processingLatch = new CountDownLatch(1); + List> ctxNodes = IntStream.range(0, RULE_DISPATCHER_POOL_SIZE * 2) + .mapToObj(x -> { + final TbContext ctx = mock(TbContext.class); // many rule nodes - many contexts + willReturn(tenantId).given(ctx).getTenantId(); + willReturn(dbCallbackExecutor).given(ctx).getDbCallbackExecutor(); + final String resultKey = "result" + x; + final TbMathNode node = spy(initNodeWithCustomFunction(ctx, "2a+3b", + new TbMathResult(TbMathArgumentType.MESSAGE_METADATA, resultKey, 1, false, true, null), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "a"), + new TbMathArgument(TbMathArgumentType.MESSAGE_BODY, "b"))); + willAnswer(invocation -> { + if (processingLatch.getCount() > 0) { + log.debug("Await on processingLatch before processMsgAsync"); + try { + assertThat(processingLatch.await(30, TimeUnit.SECONDS)).as("await on processingLatch").isTrue(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + log.debug("\uD83D\uDC0C processMsgAsync on node with expected resultKey [{}]", resultKey); + return invocation.callRealMethod(); + }).given(node).processMsgAsync(any(), any()); + willAnswer(invocation -> { + TbMsg msg = invocation.getArgument(1); + log.debug("submit originator onMsg [{}][{}]", msg.getOriginator(), msg); + return invocation.callRealMethod(); + }).given(node).onMsg(any(), any()); + return Triple.of(ctx, resultKey, node); + }) + .collect(Collectors.toList()); + + final TbMsg msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); + + ctxNodes.forEach(ctxNode -> ruleEngineDispatcherExecutor.executeAsync(() -> ctxNode.getRight().onMsg(ctxNode.getLeft(), msg))); + ctxNodes.forEach(ctxNode -> verify(ctxNode.getRight(), timeout(5000)).onMsg(eq(ctxNode.getLeft()), any())); + processingLatch.countDown(); + + SoftAssertions softly = new SoftAssertions(); + ctxNodes.forEach(ctxNode -> { + final TbContext ctx = ctxNode.getLeft(); + final String resultKey = ctxNode.getMiddle(); + ArgumentCaptor msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + verify(ctx, timeout(5000)).tellSuccess(msgCaptor.capture()); + + TbMsg resultMsg = msgCaptor.getValue(); + assertThat(resultMsg).as("result msg non null for result key " + resultKey).isNotNull(); + log.debug("asserting result key [{}] in metadata [{}]", resultKey, resultMsg.getMetaData().getData()); + softly.assertThat(resultMsg.getMetaData().getValue(resultKey)).as("asserting result key " + resultKey) + .isEqualTo("10.0"); + }); + + softly.assertAll(); + verify(ctx, never()).tellFailure(any(), any()); + } + static class RuleDispatcherExecutor extends AbstractListeningExecutor { @Override protected int getThreadPollSize() { From c28e4157e79dbf3c6e07b49351c6dbef10c2fde5 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 31 Aug 2023 00:07:35 +0200 Subject: [PATCH 007/267] TbMathNode: call processMsgAsync via BiFunction this::processMsgAsync --- .../thingsboard/rule/engine/math/TbMathNode.java | 15 ++++++++------- .../rule/engine/math/TbMathNodeTest.java | 1 - 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java index a2b809037b..d30ded0f23 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/math/TbMathNode.java @@ -82,7 +82,7 @@ import java.util.stream.Collectors; ) public class TbMathNode implements TbNode { - private static final ConcurrentMap> locks = new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.WEAK); + private static final ConcurrentMap> locks = new ConcurrentReferenceHashMap<>(16, ConcurrentReferenceHashMap.ReferenceType.WEAK); private final ThreadLocal customExpression = new ThreadLocal<>(); private TbMathNodeConfiguration config; private boolean msgBodyToJsonConversionRequired; @@ -109,21 +109,21 @@ public class TbMathNode implements TbNode { @Override public void onMsg(TbContext ctx, TbMsg msg) { var semaphoreWithQueue = locks.computeIfAbsent(msg.getOriginator(), SemaphoreWithQueue::new); - semaphoreWithQueue.getQueue().add(new TbMsgTbContext(msg, ctx)); + semaphoreWithQueue.getQueue().add(new TbMsgTbContextBiFunction(msg, ctx, this::processMsgAsync)); tryProcessQueue(semaphoreWithQueue); } - void tryProcessQueue(SemaphoreWithQueue lockAndQueue) { + void tryProcessQueue(SemaphoreWithQueue lockAndQueue) { final Semaphore semaphore = lockAndQueue.getSemaphore(); - final Queue queue = lockAndQueue.getQueue(); + final Queue queue = lockAndQueue.getQueue(); while (!queue.isEmpty()) { // The semaphore have to be acquired before EACH poll and released before NEXT poll. // Otherwise, some message will remain unprocessed in queue if (!semaphore.tryAcquire()) { return; } - TbMsgTbContext tbMsgTbContext = null; + TbMsgTbContextBiFunction tbMsgTbContext = null; try { tbMsgTbContext = queue.poll(); if (tbMsgTbContext == null) { @@ -138,7 +138,7 @@ public class TbMathNode implements TbNode { } //DO PROCESSING final TbContext ctx = tbMsgTbContext.getCtx(); - final ListenableFuture resultMsgFuture = processMsgAsync(ctx, msg); + final ListenableFuture resultMsgFuture = tbMsgTbContext.getBiFunction().apply(ctx, msg); DonAsynchron.withCallback(resultMsgFuture, resultMsg -> { try { ctx.tellSuccess(resultMsg); @@ -432,9 +432,10 @@ public class TbMathNode implements TbNode { @Data @RequiredArgsConstructor - static public class TbMsgTbContext { + static public class TbMsgTbContextBiFunction { final TbMsg msg; final TbContext ctx; + final BiFunction> biFunction; } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index c9659bad9f..bf85d6c96e 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -652,7 +652,6 @@ public class TbMathNodeTest { List> ctxNodes = IntStream.range(0, RULE_DISPATCHER_POOL_SIZE * 2) .mapToObj(x -> { final TbContext ctx = mock(TbContext.class); // many rule nodes - many contexts - willReturn(tenantId).given(ctx).getTenantId(); willReturn(dbCallbackExecutor).given(ctx).getDbCallbackExecutor(); final String resultKey = "result" + x; final TbMathNode node = spy(initNodeWithCustomFunction(ctx, "2a+3b", From bbef1cdf3fd3e8ca551d4bbac9fc96b6f62b212e Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 31 Aug 2023 00:15:10 +0200 Subject: [PATCH 008/267] TbMathNode: test optimized --- .../org/thingsboard/rule/engine/math/TbMathNodeTest.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java index bf85d6c96e..674c0efcb4 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/math/TbMathNodeTest.java @@ -678,10 +678,8 @@ public class TbMathNodeTest { return Triple.of(ctx, resultKey, node); }) .collect(Collectors.toList()); - - final TbMsg msg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", originator, new TbMsgMetaData(), JacksonUtil.newObjectNode().put("a", 2).put("b", 2).toString()); - - ctxNodes.forEach(ctxNode -> ruleEngineDispatcherExecutor.executeAsync(() -> ctxNode.getRight().onMsg(ctxNode.getLeft(), msg))); + ctxNodes.forEach(ctxNode -> ruleEngineDispatcherExecutor.executeAsync(() -> ctxNode.getRight() + .onMsg(ctxNode.getLeft(), TbMsg.newMsg("POST_TELEMETRY_REQUEST", originator, new TbMsgMetaData(), "{\"a\":2,\"b\":2}")))); ctxNodes.forEach(ctxNode -> verify(ctxNode.getRight(), timeout(5000)).onMsg(eq(ctxNode.getLeft()), any())); processingLatch.countDown(); From 7d13b034a279c53d30c6b1b8867913b6cfc76b99 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Sun, 3 Sep 2023 11:22:30 +0300 Subject: [PATCH 009/267] Migrate test to Junit 5, perform small cleanup --- .../state/DefaultDeviceStateServiceTest.java | 83 ++++++++++--------- 1 file changed, 42 insertions(+), 41 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index ceb98480c1..e03e4e94cf 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -15,13 +15,11 @@ */ package org.thingsboard.server.service.state; -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.junit.MockitoJUnitRunner; +import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DeviceIdInfo; @@ -49,16 +47,20 @@ import java.util.List; import java.util.Map; import java.util.UUID; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.willReturn; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; +import static org.mockito.Mockito.reset; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.thingsboard.server.service.state.DefaultDeviceStateService.ACTIVITY_STATE; import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_TIMEOUT; -@RunWith(MockitoJUnitRunner.class) +@ExtendWith(MockitoExtension.class) public class DefaultDeviceStateServiceTest { @Mock @@ -75,6 +77,10 @@ public class DefaultDeviceStateServiceTest { DeviceStateData deviceStateDataMock; @Mock EntityQueryRepository entityQueryRepository; + @Mock + TelemetrySubscriptionService telemetrySubscriptionService; + @Mock + NotificationRuleProcessor notificationRuleProcessor; TenantId tenantId = new TenantId(UUID.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112")); DeviceId deviceId = DeviceId.fromString("00797a3b-7aeb-4b5b-b57a-c2a810d0f112"); @@ -82,31 +88,23 @@ public class DefaultDeviceStateServiceTest { DefaultDeviceStateService service; - TelemetrySubscriptionService telemetrySubscriptionService; - - @Before + @BeforeEach public void setUp() { - service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, entityQueryRepository, null, null, mock(NotificationRuleProcessor.class))); - telemetrySubscriptionService = Mockito.mock(TelemetrySubscriptionService.class); + service = spy(new DefaultDeviceStateService(deviceService, attributesService, tsService, clusterService, partitionService, entityQueryRepository, null, null, notificationRuleProcessor)); ReflectionTestUtils.setField(service, "tsSubService", telemetrySubscriptionService); ReflectionTestUtils.setField(service, "defaultStateCheckIntervalInSec", 60); ReflectionTestUtils.setField(service, "defaultActivityStatsIntervalInSec", 60); ReflectionTestUtils.setField(service, "initFetchPackSize", 10); tpi = TopicPartitionInfo.builder().myPartition(true).build(); - Mockito.when(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).thenReturn(tpi); - Mockito.when(entityQueryRepository.findEntityDataByQueryInternal(Mockito.any())).thenReturn(new PageData<>()); - var deviceIdInfo = new DeviceIdInfo(tenantId.getId(), null, deviceId.getId()); - Mockito.when(deviceService.findDeviceIdInfos(Mockito.any())) - .thenReturn(new PageData<>(List.of(deviceIdInfo), 0, 1, false)); } @Test public void givenDeviceIdFromDeviceStatesMap_whenGetOrFetchDeviceStateData_thenNoStackOverflow() { service.deviceStates.put(deviceId, deviceStateDataMock); DeviceStateData deviceStateData = service.getOrFetchDeviceStateData(deviceId); - assertThat(deviceStateData, is(deviceStateDataMock)); - Mockito.verify(service, never()).fetchDeviceStateDataUsingEntityDataQuery(deviceId); + assertThat(deviceStateData).isEqualTo(deviceStateDataMock); + verify(service, never()).fetchDeviceStateDataUsingEntityDataQuery(deviceId); } @Test @@ -114,8 +112,8 @@ public class DefaultDeviceStateServiceTest { service.deviceStates.clear(); willReturn(deviceStateDataMock).given(service).fetchDeviceStateDataUsingEntityDataQuery(deviceId); DeviceStateData deviceStateData = service.getOrFetchDeviceStateData(deviceId); - assertThat(deviceStateData, is(deviceStateDataMock)); - Mockito.verify(service, times(1)).fetchDeviceStateDataUsingEntityDataQuery(deviceId); + assertThat(deviceStateData).isEqualTo(deviceStateDataMock); + verify(service, times(1)).fetchDeviceStateDataUsingEntityDataQuery(deviceId); } @Test @@ -151,14 +149,19 @@ public class DefaultDeviceStateServiceTest { DeviceStateData deviceStateData = service.toDeviceStateData(new EntityData(deviceId, latest, Map.of()), new DeviceIdInfo(TenantId.SYS_TENANT_ID.getId(), UUID.randomUUID(), deviceUuid)); - Assert.assertEquals(5000L, deviceStateData.getState().getInactivityTimeout()); + assertThat(deviceStateData.getState().getInactivityTimeout()).isEqualTo(5000L); } private void initStateService(long timeout) throws InterruptedException { service.stop(); - Mockito.reset(service, telemetrySubscriptionService); - ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", timeout); + reset(service, telemetrySubscriptionService); + service.setDefaultInactivityTimeoutMs(timeout); service.init(); + when(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).thenReturn(tpi); + when(entityQueryRepository.findEntityDataByQueryInternal(any())).thenReturn(new PageData<>()); + var deviceIdInfo = new DeviceIdInfo(tenantId.getId(), null, deviceId.getId()); + when(deviceService.findDeviceIdInfos(any())) + .thenReturn(new PageData<>(List.of(deviceIdInfo), 0, 1, false)); PartitionChangeEvent event = new PartitionChangeEvent(this, new QueueKey(ServiceType.TB_CORE), Collections.singleton(tpi)); service.onApplicationEvent(event); Thread.sleep(100); @@ -185,7 +188,7 @@ public class DefaultDeviceStateServiceTest { service.checkStates(); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); long increase = 100; long newTimeout = System.currentTimeMillis() - deviceState.getLastActivityTime() + increase; @@ -196,7 +199,7 @@ public class DefaultDeviceStateServiceTest { service.checkStates(); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); activityVerify(true); @@ -223,18 +226,18 @@ public class DefaultDeviceStateServiceTest { service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); activityVerify(true); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); long increase = 100; long newTimeout = System.currentTimeMillis() - deviceState.getLastActivityTime() + increase; service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), any(), any()); Thread.sleep(defaultTimeout + increase); service.checkStates(); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); activityVerify(true); @@ -264,11 +267,11 @@ public class DefaultDeviceStateServiceTest { service.checkStates(); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); long newTimeout = 1; Thread.sleep(newTimeout); - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), any(), any()); } @Test @@ -289,16 +292,14 @@ public class DefaultDeviceStateServiceTest { service.onDeviceActivity(tenantId, deviceId, System.currentTimeMillis()); activityVerify(true); - Mockito.reset(telemetrySubscriptionService); - - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), any(), any()); long newTimeout = 1; Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, defaultTimeout); activityVerify(true); @@ -327,17 +328,17 @@ public class DefaultDeviceStateServiceTest { Thread.sleep(defaultTimeout); service.checkStates(); activityVerify(false); - Mockito.reset(telemetrySubscriptionService); + reset(telemetrySubscriptionService); long newTimeout = 1; Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); - Mockito.verify(telemetrySubscriptionService, Mockito.never()).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.any(), Mockito.any()); + verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), any(), any()); } private void activityVerify(boolean isActive) { - Mockito.verify(telemetrySubscriptionService, Mockito.times(1)).saveAttrAndNotify(Mockito.any(), Mockito.eq(deviceId), Mockito.any(), Mockito.eq("active"), Mockito.eq(isActive), Mockito.any()); + verify(telemetrySubscriptionService, times(1)).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), eq(isActive), any()); } } \ No newline at end of file From 4180866cccd491917b3eb1779cdc6bc8b71ae616 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Wed, 6 Sep 2023 18:37:42 +0300 Subject: [PATCH 010/267] Add parameterized test to cover `updateInactivityStateIfExpired()` --- .../state/DefaultDeviceStateServiceTest.java | 183 +++++++++++++++++- 1 file changed, 182 insertions(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index e03e4e94cf..10c507f884 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -18,6 +18,10 @@ package org.thingsboard.server.service.state; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; @@ -25,10 +29,13 @@ import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.DeviceIdInfo; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.notification.rule.trigger.DeviceActivityTrigger; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.query.EntityData; import org.thingsboard.server.common.data.query.EntityKeyType; import org.thingsboard.server.common.data.query.TsValue; +import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.notification.NotificationRuleProcessor; import org.thingsboard.server.common.msg.queue.ServiceType; @@ -46,10 +53,13 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; import static org.mockito.BDDMockito.willReturn; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; @@ -57,7 +67,9 @@ import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import static org.thingsboard.server.common.data.DataConstants.SERVER_SCOPE; import static org.thingsboard.server.service.state.DefaultDeviceStateService.ACTIVITY_STATE; +import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_ALARM_TIME; import static org.thingsboard.server.service.state.DefaultDeviceStateService.INACTIVITY_TIMEOUT; @ExtendWith(MockitoExtension.class) @@ -341,4 +353,173 @@ public class DefaultDeviceStateServiceTest { verify(telemetrySubscriptionService, times(1)).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), eq(isActive), any()); } -} \ No newline at end of file + @Test + public void givenStateDataIsNull_whenUpdateInactivityTimeoutIfExpired_thenShouldCleanupDevice() { + // GIVEN + service.deviceStates.put(deviceId, deviceStateDataMock); + + // WHEN + service.updateInactivityStateIfExpired(System.currentTimeMillis(), deviceId, null); + + // THEN + assertThat(service.deviceStates.get(deviceId)).isNull(); + assertThat(service.deviceStates.size()).isEqualTo(0); + assertThat(service.deviceStates.isEmpty()).isTrue(); + } + + @Test + public void givenNotMyPartition_whenUpdateInactivityTimeoutIfExpired_thenShouldCleanupDevice() { + // GIVEN + long currentTime = System.currentTimeMillis(); + + DeviceState deviceState = DeviceState.builder() + .active(true) + .lastConnectTime(currentTime - 8000) + .lastActivityTime(currentTime - 4000) + .lastDisconnectTime(0) + .lastInactivityAlarmTime(0) + .inactivityTimeout(3000) + .build(); + + DeviceStateData stateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .deviceCreationTime(currentTime - 10000) + .state(deviceState) + .build(); + + service.deviceStates.put(deviceId, stateData); + + var notMyTpi = TopicPartitionInfo.builder().myPartition(false).build(); + given(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).willReturn(notMyTpi); + + // WHEN + service.updateInactivityStateIfExpired(System.currentTimeMillis(), deviceId, stateData); + + // THEN + assertThat(service.deviceStates.get(deviceId)).isNull(); + assertThat(service.deviceStates.size()).isEqualTo(0); + assertThat(service.deviceStates.isEmpty()).isTrue(); + } + + @ParameterizedTest + @MethodSource("provideParametersForUpdateInactivityStateIfExpired") + public void givenTestParameters_whenUpdateInactivityStateIfExpired_thenShouldBeInTheExpectedStateAndPerformExpectedActions( + boolean activityState, long ts, long lastActivityTime, long lastInactivityAlarmTime, long inactivityTimeout, long deviceCreationTime, + boolean expectedActivityState, long expectedLastInactivityAlarmTime, boolean shouldUpdateActivityStateToInactive + ) { + // GIVEN + var state = DeviceState.builder() + .active(activityState) + .lastActivityTime(lastActivityTime) + .lastInactivityAlarmTime(lastInactivityAlarmTime) + .inactivityTimeout(inactivityTimeout) + .build(); + + var deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .deviceCreationTime(deviceCreationTime) + .metaData(new TbMsgMetaData()) + .state(state) + .build(); + + if (shouldUpdateActivityStateToInactive) { + given(partitionService.resolve(ServiceType.TB_CORE, tenantId, deviceId)).willReturn(tpi); + } + + // WHEN + service.updateInactivityStateIfExpired(ts, deviceId, deviceStateData); + + // THEN + assertThat(state.isActive()).isEqualTo(expectedActivityState); + assertThat(state.getLastInactivityAlarmTime()).isEqualTo(expectedLastInactivityAlarmTime); + + if (shouldUpdateActivityStateToInactive) { + then(telemetrySubscriptionService).should().saveAttrAndNotify( + eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(SERVER_SCOPE), eq(ACTIVITY_STATE), eq(false), any() + ); + + var msgCaptor = ArgumentCaptor.forClass(TbMsg.class); + then(clusterService).should().pushMsgToRuleEngine(eq(tenantId), eq(deviceId), msgCaptor.capture(), any()); + var actualMsg = msgCaptor.getValue(); + assertThat(actualMsg.getType()).isEqualTo(TbMsgType.INACTIVITY_EVENT.name()); + assertThat(actualMsg.getOriginator()).isEqualTo(deviceId); + + var notificationCaptor = ArgumentCaptor.forClass(DeviceActivityTrigger.class); + then(notificationRuleProcessor).should().process(notificationCaptor.capture()); + var actualNotification = notificationCaptor.getValue(); + assertThat(actualNotification.getTenantId()).isEqualTo(tenantId); + assertThat(actualNotification.getDeviceId()).isEqualTo(deviceId); + assertThat(actualNotification.isActive()).isFalse(); + + then(telemetrySubscriptionService).should().saveAttrAndNotify( + eq(TenantId.SYS_TENANT_ID), eq(deviceId), eq(SERVER_SCOPE), + eq(INACTIVITY_ALARM_TIME), eq(expectedLastInactivityAlarmTime), any() + ); + } + } + + private static Stream provideParametersForUpdateInactivityStateIfExpired() { + return Stream.of( + Arguments.of(false, 100, 70, 90, 70, 60, false, 90, false), + + Arguments.of(false, 100, 40, 50, 70, 10, false, 50, false), + + Arguments.of(false, 100, 25, 60, 75, 25, false, 60, false), + + Arguments.of(false, 100, 60, 70, 10, 50, false, 70, false), + + Arguments.of(false, 100, 10, 15, 90, 10, false, 15, false), + + Arguments.of(false, 100, 0, 40, 75, 0, false, 40, false), + + Arguments.of(true, 100, 90, 80, 80, 50, true, 80, false), + + Arguments.of(true, 100, 95, 90, 10, 50, true, 90, false), + + Arguments.of(true, 100, 10, 10, 90, 10, false, 100, true), + + Arguments.of(true, 100, 10, 10, 90, 11, true, 10, false), + + Arguments.of(true, 100, 15, 10, 85, 5, false, 100, true), + + Arguments.of(true, 100, 15, 10, 75, 5, false, 100, true), + + Arguments.of(true, 100, 95, 90, 5, 50, false, 100, true), + + Arguments.of(true, 100, 0, 0, 101, 0, true, 0, false), + + Arguments.of(true, 100, 0, 0, 100, 0, false, 100, true), + + Arguments.of(true, 100, 0, 0, 99, 0, false, 100, true), + + Arguments.of(true, 100, 0, 0, 120, 10, true, 0, false), + + Arguments.of(true, 100, 50, 0, 100, 0, true, 0, false), + + Arguments.of(true, 100, 10, 0, 91, 0, true, 0, false), + + Arguments.of(true, 100, 90, 0, 10, 0, false, 100, true), + + Arguments.of(true, 100, 100, 100, 1, 0, true, 100, false), + + Arguments.of(true, 100, 100, 100, 100, 100, true, 100, false), + + Arguments.of(false, 100, 59, 60, 30, 10, false, 60, false), + + Arguments.of(true, 100, 60, 60, 30, 10, false, 100, true), + + Arguments.of(true, 100, 61, 60, 30, 10, false, 100, true), + + Arguments.of(true, 0, 0, 0, 1, 0, true, 0, false), + + Arguments.of(true, 0, 0, 0, 0, 0, false, 0, true), + + Arguments.of(true, 100, 90, 80, 20, 70, true, 80, false), + + Arguments.of(true, 100, 80, 90, 30, 70, true, 90, false) + ); + } + +} From 5e6dd652d7fb85b45251d2d70427f8108a81b5ce Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 7 Sep 2023 12:41:20 +0300 Subject: [PATCH 011/267] Adjust timeout passed since device creation time check to be not strict --- .../server/service/state/DefaultDeviceStateService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 f9afb5b2e5..23276dc104 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 @@ -487,7 +487,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService Date: Thu, 7 Sep 2023 15:58:19 +0300 Subject: [PATCH 012/267] Add decrease inactivity timeout test with a controlled time --- .../state/DefaultDeviceStateService.java | 20 +++++--- .../state/DefaultDeviceStateServiceTest.java | 51 +++++++++++++++++++ 2 files changed, 63 insertions(+), 8 deletions(-) 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 23276dc104..1f9239cea3 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 @@ -223,7 +223,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService= deviceState.getLastActivityTime()) { deviceState.setLastInactivityAlarmTime(0L); @@ -425,7 +425,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService { log.debug("Calculating state updates. tpi {} for {} devices", tpi.getFullTopicName(), deviceIds.size()); Set idsFromRemovedTenant = new HashSet<>(); @@ -455,7 +455,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService> stats = new HashMap<>(); for (DeviceStateData stateData : deviceStates.values()) { Pair tenantDevicesActivity = stats.computeIfAbsent(stateData.getTenantId(), @@ -798,7 +798,7 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value)); } else { tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); @@ -809,13 +809,17 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService(deviceId, key, value)); } else { tsSubService.saveAttrAndNotify(TenantId.SYS_TENANT_ID, deviceId, SERVER_SCOPE, key, value, new TelemetrySaveCallback<>(deviceId, key, value)); } } + long getCurrentTimeMillis() { + return System.currentTimeMillis(); + } + private static class TelemetrySaveCallback implements FutureCallback { private final DeviceId deviceId; private final String key; diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index b06bbab0de..d03771cde3 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -54,6 +54,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.UUID; +import java.util.concurrent.atomic.AtomicLong; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; @@ -356,6 +357,56 @@ public class DefaultDeviceStateServiceTest { verify(telemetrySubscriptionService, times(1)).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), eq(isActive), any()); } + @ParameterizedTest + @MethodSource("provideParametersForDecreaseInactivityTimeout") + public void givenTestParameters_whenOnDeviceInactivityTimeout_thenShouldBeInTheExpectedStateAndPerformExpectedActions( + boolean activityState, long newInactivityTimeout, long timeIncrement, boolean expectedActivityState + ) throws Exception { + // GIVEN + long defaultInactivityTimeout = 10000; + initStateService(defaultInactivityTimeout); + + var currentTime = new AtomicLong(System.currentTimeMillis()); + + DeviceState deviceState = DeviceState.builder() + .active(activityState) + .lastActivityTime(currentTime.get()) + .inactivityTimeout(defaultInactivityTimeout) + .build(); + + DeviceStateData deviceStateData = DeviceStateData.builder() + .tenantId(tenantId) + .deviceId(deviceId) + .state(deviceState) + .metaData(new TbMsgMetaData()) + .build(); + + service.deviceStates.put(deviceId, deviceStateData); + service.getPartitionedEntities(tpi).add(deviceId); + + given(service.getCurrentTimeMillis()).willReturn(currentTime.addAndGet(timeIncrement)); + + // WHEN + service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newInactivityTimeout); + + // THEN + assertThat(deviceState.getInactivityTimeout()).isEqualTo(newInactivityTimeout); + assertThat(deviceState.isActive()).isEqualTo(expectedActivityState); + if (activityState && !expectedActivityState) { + then(telemetrySubscriptionService).should().saveAttrAndNotify( + any(), eq(deviceId), any(), eq(ACTIVITY_STATE), eq(false), any() + ); + } + } + + private static Stream provideParametersForDecreaseInactivityTimeout() { + return Stream.of( + Arguments.of(true, 1, 0, true), + + Arguments.of(true, 1, 1, false) + ); + } + @Test public void givenStateDataIsNull_whenUpdateInactivityTimeoutIfExpired_thenShouldCleanupDevice() { // GIVEN From a4d4e8c6eb6f621ab441454b2b40c9fc026c348a Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 7 Sep 2023 15:59:03 +0300 Subject: [PATCH 013/267] Remove redundant sleep --- .../server/service/state/DefaultDeviceStateServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index d03771cde3..b9716320a6 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -347,7 +347,6 @@ public class DefaultDeviceStateServiceTest { reset(telemetrySubscriptionService); long newTimeout = 1; - Thread.sleep(newTimeout); service.onDeviceInactivityTimeoutUpdate(tenantId, deviceId, newTimeout); verify(telemetrySubscriptionService, never()).saveAttrAndNotify(any(), eq(deviceId), any(), eq(ACTIVITY_STATE), any(), any()); From 5387f545d60377540ec31aade2a6c35f8fe2a0eb Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 8 Sep 2023 16:47:44 +0300 Subject: [PATCH 014/267] edge downlink table - fixed error in case unknown entity type or action. added missing types/actions --- .../components/edge/edge-downlink-table-config.ts | 10 ++++++++-- ui-ngx/src/app/shared/models/edge.models.ts | 14 ++++++++++++-- .../src/assets/locale/locale.constant-en_US.json | 5 +++++ 3 files changed, 25 insertions(+), 4 deletions(-) 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 5889ebcdf2..f970ad80f4 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 @@ -107,9 +107,15 @@ export class EdgeDownlinkTableConfig extends EntityTableConfig('createdTime', 'event.event-time', this.datePipe, '120px'), new EntityTableColumn('type', 'event.type', '25%', - entity => this.translate.instant(edgeEventTypeTranslations.get(entity.type)), entity => ({}), false), + entity => { + let key = edgeEventTypeTranslations.get(entity.type); + return key ? this.translate.instant(key) : entity.type; + }, entity => ({}), false), new EntityTableColumn('action', 'edge.event-action', '25%', - entity => this.translate.instant(edgeEventActionTypeTranslations.get(entity.action)), entity => ({}), false), + entity => { + let key = edgeEventActionTypeTranslations.get(entity.action); + return key ? this.translate.instant(key) : entity.action; + }, entity => ({}), false), new EntityTableColumn('entityId', 'edge.entity-id', '40%', (entity) => entity.entityId ? entity.entityId : '', () => ({}), false), new EntityTableColumn('status', 'event.status', '10%', diff --git a/ui-ngx/src/app/shared/models/edge.models.ts b/ui-ngx/src/app/shared/models/edge.models.ts index 372a910402..1acfa2ca28 100644 --- a/ui-ngx/src/app/shared/models/edge.models.ts +++ b/ui-ngx/src/app/shared/models/edge.models.ts @@ -59,9 +59,12 @@ export enum EdgeEventType { CUSTOMER = 'CUSTOMER', RELATION = 'RELATION', TENANT = 'TENANT', + TENANT_PROFILE = 'TENANT_PROFILE', WIDGETS_BUNDLE = 'WIDGETS_BUNDLE', WIDGET_TYPE = 'WIDGET_TYPE', - ADMIN_SETTINGS = 'ADMIN_SETTINGS' + ADMIN_SETTINGS = 'ADMIN_SETTINGS', + OTA_PACKAGE = 'OTA_PACKAGE', + QUEUE = 'QUEUE' } export enum EdgeEventActionType { @@ -80,6 +83,8 @@ export enum EdgeEventActionType { RPC_CALL = 'RPC_CALL', ALARM_ACK = 'ALARM_ACK', ALARM_CLEAR = 'ALARM_CLEAR', + ALARM_ASSIGNED = 'ALARM_ASSIGNED', + ALARM_UNASSIGNED = 'ALARM_UNASSIGNED', ASSIGNED_TO_EDGE = 'ASSIGNED_TO_EDGE', UNASSIGNED_FROM_EDGE = 'UNASSIGNED_FROM_EDGE', CREDENTIALS_REQUEST = 'CREDENTIALS_REQUEST', @@ -107,9 +112,12 @@ export const edgeEventTypeTranslations = new Map( [EdgeEventType.CUSTOMER, 'edge-event.type-customer'], [EdgeEventType.RELATION, 'edge-event.type-relation'], [EdgeEventType.TENANT, 'edge-event.type-tenant'], + [EdgeEventType.TENANT_PROFILE, 'edge-event.type-tenant-profile'], [EdgeEventType.WIDGETS_BUNDLE, 'edge-event.type-widgets-bundle'], [EdgeEventType.WIDGET_TYPE, 'edge-event.type-widgets-type'], - [EdgeEventType.ADMIN_SETTINGS, 'edge-event.type-admin-settings'] + [EdgeEventType.ADMIN_SETTINGS, 'edge-event.type-admin-settings'], + [EdgeEventType.OTA_PACKAGE, 'edge-event.type-ota-package'], + [EdgeEventType.QUEUE, 'edge-event.type-queue'] ] ); @@ -130,6 +138,8 @@ export const edgeEventActionTypeTranslations = new Map Date: Fri, 8 Sep 2023 16:53:33 +0300 Subject: [PATCH 015/267] UI: changed validation hints of add telemetry dialog to more precise --- .../attribute/add-attribute-dialog.component.html | 6 +++--- .../components/attribute/add-attribute-dialog.component.ts | 5 ++--- ui-ngx/src/assets/locale/locale.constant-en_US.json | 2 ++ 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html index 17e31854cc..af2a959424 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html @@ -17,7 +17,7 @@ -->
-

{{ title | translate }}

+

{{ (isTelemetry ? 'attribute.add-telemetry' : 'attribute.add') | translate }}

-
- - -
-
-
- - {{ 'gateway.remote-configuration' | translate }} - info - - - - {{ 'gateway.remote-shell' | translate }} - info - - - - gateway.thingsboard-host - - info_outlined - - - {{ 'gateway.thingsboard-host-required' | translate }} - - - - gateway.thingsboard-port - - - {{'gateway.thingsboard-port-required' | translate }} - - - {{'gateway.thingsboard-port-min' | translate }} - - - {{'gateway.thingsboard-port-max' | translate }} - - - {{'gateway.thingsboard-port-pattern' | translate }} - - info_outlined - - - -
-
-
-
security.security
-
- - {{ securityType.value | translate }} - -
- - security.access-token - - - {{'security.access-token-required' | translate}} - - info_outlined - - - - security.clientId - - - {{'security.clientId-required' | translate}} - - info_outlined - - - - security.username - - - {{'security.username-required' | translate}} - - info_outlined - - - - security.password - - info_outlined - - - - - - - - - - -
-
-
+ +

gateway.gateway-configuration

+ + +
+ + +
+
+
+ + {{ 'gateway.remote-configuration' | translate }} + +
+
+ + {{ 'gateway.remote-shell' | translate }} + +
+
+ + gateway.thingsboard-host + + info_outlined + + + {{ 'gateway.thingsboard-host-required' | translate }} + + + + gateway.thingsboard-port + + + {{ 'gateway.thingsboard-port-required' | translate }} + + + {{ 'gateway.thingsboard-port-min' | translate }} + + + {{ 'gateway.thingsboard-port-max' | translate }} + + + {{ 'gateway.thingsboard-port-pattern' | translate }} + + info_outlined + + +
- - -
-
-
- - gateway.logs.date-format - - - {{'gateway.logs.date-format-required' | translate }} - - info_outlined - - - - gateway.logs.log-format - - - {{'gateway.logs.log-format-required' | translate }} - - info_outlined - - -
-
-
-
gateway.logs.remote
- - {{ 'gateway.logs.remote-logs' | translate }} - info +
+
security.security
+ + + {{ securityType.value | translate }} + + + security.access-token + + + {{ 'security.access-token-required' | translate }} + + info_outlined + + +
+ + security.clientId + + + {{ 'security.clientId-required' | translate }} + + info_outlined + + + + security.username + + + {{ 'security.username-required' | translate }} + + info_outlined - - - gateway.logs.level - - {{logLevel}} -
-
-
gateway.logs.local
-
- - {{ logConfig.value }} - -
- - gateway.logs.level - - {{logLevel}} - - - - gateway.logs.file-path - - - {{'gateway.logs.file-path-required' | translate }} - - -
- - gateway.logs.saving-period - - - {{'gateway.logs.saving-period-required' | translate }} - - - {{'gateway.logs.saving-period-min' | translate }} - - - - - - - {{period.value | translate}} - - - -
- - gateway.logs.backup-count - - - {{'gateway.logs.backup-count-required' | translate }} - - - {{'gateway.logs.backup-count-min' | translate }} - - info_outlined - - -
-
-
+ + security.password + + info_outlined + + + + + +
- - -
-
-
gateway.storage - {{'gateway.hints.storage' | translate}} -
-
- - - {{ storageType.value | translate }} - - -
- - {{'gateway.hints.' + gatewayConfigGroup.get('storage.type').value | translate}} -
- - gateway.storage-read-record-count - - - {{'gateway.storage-read-record-count-required' | translate}} - - - {{'gateway.storage-read-record-count-min' | translate}} - - - {{'gateway.storage-read-record-count-pattern' | translate}} - - info_outlined - - - - gateway.storage-max-records - - - {{'gateway.storage-max-records-required' | translate}} - - - {{'gateway.storage-max-records-min' | translate}} - - - {{'gateway.storage-max-records-pattern' | translate}} - - info_outlined - - - - gateway.storage-data-folder-path - - - {{'gateway.storage-data-folder-path-required' | translate}} - - info_outlined - - - - gateway.storage-max-files - - - {{'gateway.storage-max-files-required' | translate}} - - - {{'gateway.storage-max-files-min' | translate}} - - - {{'gateway.storage-max-files-pattern' | translate}} - - info_outlined - - - - gateway.storage-max-read-record-count - - - {{'gateway.storage-max-read-record-count-required' | translate}} - - - {{'gateway.storage-max-read-record-count-min' | translate}} - - - {{'gateway.storage-max-read-record-count-pattern' | translate}} - - info_outlined - - - - gateway.storage-max-file-records - - - {{'gateway.storage-max-records-required' | translate}} - - - {{'gateway.storage-max-records-min' | translate}} - - - {{'gateway.storage-max-records-pattern' | translate}} - - info_outlined - - - - gateway.storage-path - - - {{'gateway.storage-path-required' | translate}} - - info_outlined - - - - gateway.messages-ttl-check-in-hours - - - {{'gateway.messages-ttl-check-in-hours-required' | translate}} - - - {{'gateway.messages-ttl-check-in-hours-min' | translate}} - - - {{'gateway.messages-ttl-check-in-hours-pattern' | translate}} - - info_outlined - - - - gateway.messages-ttl-in-days - - - {{'gateway.messages-ttl-in-days-required' | translate}} - - - {{'gateway.messages-ttl-in-days-min' | translate}} - - - {{'gateway.messages-ttl-in-days-pattern' | translate}} - - info_outlined - - -
-
-
+
+
+ +
+
+
+ + gateway.logs.date-format + + + {{ 'gateway.logs.date-format-required' | translate }} + + info_outlined + + + + gateway.logs.log-format + + + {{ 'gateway.logs.log-format-required' | translate }} + + info_outlined + + +
- - -
-
-
- - {{ 'gateway.grpc' | translate }} - - - {{ 'gateway.permit-without-calls' | translate }} - info - - - - gateway.server-port - - info_outlined - - - {{'gateway.thingsboard-port-required' | translate }} - - - {{'gateway.thingsboard-port-min' | translate }} - - - {{'gateway.thingsboard-port-max' | translate }} - - - {{'gateway.thingsboard-port-pattern' | translate }} - - - - gateway.grpc-keep-alive-timeout - - info_outlined - - - {{'gateway.grpc-keep-alive-timeout-required' | translate }} - - - {{'gateway.grpc-keep-alive-timeout-min' | translate }} - - - {{'gateway.grpc-keep-alive-timeout-pattern' | translate }} - - - - gateway.grpc-keep-alive - - info_outlined - - - {{'gateway.grpc-keep-alive-required' | translate }} - - - {{'gateway.grpc-keep-alive-min' | translate }} - - - {{'gateway.grpc-keep-alive-pattern' | translate }} - - - - gateway.grpc-min-time-between-pings - - info_outlined - - - {{'gateway.grpc-min-time-between-pings-required' | translate }} - - - {{'gateway.grpc-min-time-between-pings-min' | translate }} - - - {{'gateway.grpc-min-time-between-pings-pattern' | translate }} - - - - gateway.grpc-max-pings-without-data - - info_outlined - - - {{'gateway.grpc-max-pings-without-data-required' | translate }} - - - {{'gateway.grpc-max-pings-without-data-min' | translate }} - - - {{'gateway.grpc-max-pings-without-data-pattern' | translate }} - - - - gateway.grpc-min-ping-interval-without-data - - info_outlined - - - {{'gateway.grpc-min-ping-interval-without-data-required' | translate }} - - - {{'gateway.grpc-min-ping-interval-without-data-min' | translate }} - - - {{'gateway.grpc-min-ping-interval-without-data-pattern' | translate }} - - -
-
+
+
gateway.logs.remote
+
+ + {{ 'gateway.logs.remote-logs' | translate }} + +
+ + gateway.logs.level + + {{ logLevel }} + +
- - -
-
-
- - {{ 'gateway.statistics.statistics' | translate }} - - - gateway.statistics.send-period - - - {{'gateway.statistics.send-period-required' | translate }} - +
+
gateway.logs.local
+ + {{ localLogsConfigTranslateMap.get(logConfig) }} + + +
+ + gateway.logs.level + + {{ logLevel }} + + + + gateway.logs.file-path + + + {{ 'gateway.logs.file-path-required' | translate }} + + +
+
+
+ + gateway.logs.saving-period + - {{'gateway.statistics.send-period-min' | translate }} + *ngIf="gatewayConfigGroup.get('logs.local.' + logSelector.value + '.savingTime').hasError('required')"> + {{ 'gateway.logs.saving-period-required' | translate }} - {{'gateway.statistics.send-period-pattern' | translate }} + *ngIf="gatewayConfigGroup.get('logs.local.' + logSelector.value + '.savingTime').hasError('min')"> + {{ 'gateway.logs.saving-period-min' | translate }} + + + + {{ period.value | translate }} + + +
+ + gateway.logs.backup-count + + + {{ 'gateway.logs.backup-count-required' | translate }} + + + {{ 'gateway.logs.backup-count-min' | translate }} + + info_outlined + +
-
-
{{"gateway.statistics.commands" |translate}} - - {{'gateway.hints.commands' | translate}}
-
-
- - - gateway.statistics.attribute-name - - - {{'gateway.statistics.attribute-name-required' | translate }} - - info_outlined - - - - gateway.statistics.timeout - - - {{'gateway.statistics.timeout-required' | translate }} - - - {{'gateway.statistics.timeout-min' | translate }} - - - {{'gateway.statistics.timeout-pattern' | translate }} - - info_outlined - - - - gateway.statistics.command - - - {{'gateway.statistics.command-required' | translate }} - - info_outlined - - - - -
- -
-
+
- - -
-
-
- - {{ 'gateway.checking-device-activity' | translate }} - - {{'gateway.hints.check-device-activity' | translate}} -
-
- - gateway.inactivity-timeout-seconds - - - {{'gateway.inactivity-timeout-seconds-required' | translate }} - - - {{'gateway.inactivity-timeout-seconds-min' | translate }} +
+ + +
+
+
gateway.storage
+
gateway.hints.storage
+ + + {{ storageTypesTranslationMap.get(storageType) | translate }} + + +
{{ 'gateway.hints.' + gatewayConfigGroup.get('storage.type').value | translate }}
+ +
+ + gateway.storage-read-record-count + + + {{ 'gateway.storage-read-record-count-required' | translate }} + + + {{ 'gateway.storage-read-record-count-min' | translate }} + + + {{ 'gateway.storage-read-record-count-pattern' | translate }} + + info_outlined + + + + gateway.storage-max-records + + + {{ 'gateway.storage-max-records-required' | translate }} + + + {{ 'gateway.storage-max-records-min' | translate }} + + + {{ 'gateway.storage-max-records-pattern' | translate }} + + info_outlined + + +
+
+
+ + gateway.storage-data-folder-path + + + {{ 'gateway.storage-data-folder-path-required' | translate }} info_outlined + matTooltip="{{ 'gateway.hints.data-folder' | translate }}">info_outlined - - gateway.inactivity-check-period-seconds - - - {{'gateway.inactivity-check-period-seconds-required' | translate }} + + gateway.storage-max-files + + + {{ 'gateway.storage-max-files-required' | translate }} - - {{'gateway.inactivity-check-period-seconds-min' | translate }} + + {{ 'gateway.storage-max-files-min' | translate }} - info_outlined + + {{ 'gateway.storage-max-files-pattern' | translate }} + + info_outlined
-
-
-
gateway.advanced
-
- - gateway.min-pack-send-delay - - - {{ 'gateway.min-pack-send-delay-required' | translate }} +
+ + gateway.storage-max-read-record-count + + + {{ 'gateway.storage-max-read-record-count-required' | translate }} - - {{ 'gateway.min-pack-send-delay-min' | translate }} + + {{ 'gateway.storage-max-read-record-count-min' | translate }} - info_outlined + + {{ 'gateway.storage-max-read-record-count-pattern' | translate }} + + info_outlined - - gateway.mqtt-qos - - - {{ 'gateway.mqtt-qos-required' | translate}} + + gateway.storage-max-file-records + + + {{ 'gateway.storage-max-records-required' | translate }} - - {{ 'gateway.mqtt-qos-range' | translate}} + + {{ 'gateway.storage-max-records-min' | translate }} - - {{ 'gateway.mqtt-qos-range' | translate}} + + {{ 'gateway.storage-max-records-pattern' | translate }} - info_outlined + info_outlined - - gateway.statistics.check-connectors-configuration - - - {{'gateway.statistics.check-connectors-configuration-required' | translate }} +
+ +
+
+ + gateway.storage-path + + + {{ 'gateway.storage-path-required' | translate }} + + info_outlined + + + + gateway.messages-ttl-check-in-hours + + + {{ 'gateway.messages-ttl-check-in-hours-required' | translate }} - - {{'gateway.statistics.check-connectors-configuration-min' | translate }} + + {{ 'gateway.messages-ttl-check-in-hours-min' | translate }} - - {{'gateway.statistics.check-connectors-configuration-pattern' | translate }} + + {{ 'gateway.messages-ttl-check-in-hours-pattern' | translate }} + info_outlined +
+ + gateway.messages-ttl-in-days + + + {{ 'gateway.messages-ttl-in-days-required' | translate }} + + + {{ 'gateway.messages-ttl-in-days-min' | translate }} + + + {{ 'gateway.messages-ttl-in-days-pattern' | translate }} + + info_outlined + + +
+ +
+
+ + +
+
+ + {{ 'gateway.grpc' | translate }} + +
+ + {{ 'gateway.permit-without-calls' | translate }} + +
+
+
+ + gateway.server-port + + info_outlined + + + {{ 'gateway.thingsboard-port-required' | translate }} + + + {{ 'gateway.thingsboard-port-min' | translate }} + + + {{ 'gateway.thingsboard-port-max' | translate }} + + + {{ 'gateway.thingsboard-port-pattern' | translate }} + + + + gateway.grpc-keep-alive-timeout + + info_outlined + + + {{ 'gateway.grpc-keep-alive-timeout-required' | translate }} + + + {{ 'gateway.grpc-keep-alive-timeout-min' | translate }} + + + {{ 'gateway.grpc-keep-alive-timeout-pattern' | translate }} + + +
+
+ + gateway.grpc-keep-alive + + info_outlined + + + {{ 'gateway.grpc-keep-alive-required' | translate }} + + + {{ 'gateway.grpc-keep-alive-min' | translate }} + + + {{ 'gateway.grpc-keep-alive-pattern' | translate }} + + + + gateway.grpc-min-time-between-pings + + info_outlined + + + {{ 'gateway.grpc-min-time-between-pings-required' | translate }} + + + {{ 'gateway.grpc-min-time-between-pings-min' | translate }} + + + {{ 'gateway.grpc-min-time-between-pings-pattern' | translate }} + + +
+
+ + gateway.grpc-max-pings-without-data + + info_outlined + + + {{ 'gateway.grpc-max-pings-without-data-required' | translate }} + + + {{ 'gateway.grpc-max-pings-without-data-min' | translate }} + + + {{ 'gateway.grpc-max-pings-without-data-pattern' | translate }} + + + + gateway.grpc-min-ping-interval-without-data + + info_outlined + + + {{ 'gateway.grpc-min-ping-interval-without-data-required' | translate }} + + + {{ 'gateway.grpc-min-ping-interval-without-data-min' | translate }} + + + {{ 'gateway.grpc-min-ping-interval-without-data-pattern' | translate }} + + +
+
+
+
+
+ +
+
+ + {{ 'gateway.statistics.statistics' | translate }} + + + gateway.statistics.send-period + + + {{ 'gateway.statistics.send-period-required' | translate }} + + + {{ 'gateway.statistics.send-period-min' | translate }} + + + {{ 'gateway.statistics.send-period-pattern' | translate }} + + +
+
+
gateway.statistics.commands
+
gateway.hints.commands
+ +
+
+
+ + gateway.statistics.attribute-name + + + {{ 'gateway.statistics.attribute-name-required' | translate }} + + info_outlined + + + + gateway.statistics.timeout + + + {{ 'gateway.statistics.timeout-required' | translate }} + + + {{ 'gateway.statistics.timeout-min' | translate }} + + + {{ 'gateway.statistics.timeout-pattern' | translate }} + + info_outlined + + +
+ + gateway.statistics.command + + + {{ 'gateway.statistics.command-required' | translate }} + + info_outlined + + +
+
- + +
- - -
- - - -
- +
+
+ +
+
+
+ + {{ 'gateway.checking-device-activity' | translate }} + +
+
+ + gateway.inactivity-timeout-seconds + + + {{ 'gateway.inactivity-timeout-seconds-required' | translate }} + + + {{ 'gateway.inactivity-timeout-seconds-min' | translate }} + + info_outlined + + + + gateway.inactivity-check-period-seconds + + + {{ 'gateway.inactivity-check-period-seconds-required' | translate }} + + + {{ 'gateway.inactivity-check-period-seconds-min' | translate }} + + info_outlined + + +
+
+
+
gateway.advanced
+
+ + gateway.min-pack-send-delay + + + {{ 'gateway.min-pack-send-delay-required' | translate }} + + + {{ 'gateway.min-pack-send-delay-min' | translate }} + + info_outlined + + + + gateway.mqtt-qos + + + {{ 'gateway.mqtt-qos-required' | translate }} + + + {{ 'gateway.mqtt-qos-range' | translate }} + + + {{ 'gateway.mqtt-qos-range' | translate }} + + info_outlined + + +
+ + gateway.statistics.check-connectors-configuration + + + {{ 'gateway.statistics.check-connectors-configuration-required' | translate }} + + + {{ 'gateway.statistics.check-connectors-configuration-min' | translate }} + + + {{ 'gateway.statistics.check-connectors-configuration-pattern' | translate }} + + +
+
+
+ +
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss index 1bf599727d..803654734f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss @@ -16,14 +16,13 @@ :host { width: 100%; height: 100%; - display: block; + display: flex; + flex-direction: column; - .mat-icon { - color: rgba(0, 0, 0, .12); - } - - .tb-form-panel { - margin-bottom: 20px; + .configuration-block { + display: flex; + flex-direction: column; + gap: 16px; } .mat-toolbar { @@ -31,113 +30,37 @@ color: rgba(0, 0, 0, .87) !important; } - .mat-content { - .expansion-panel-header { - font-weight: 600; - color: rgba(0, 0, 0, .87) !important; - } - - mat-slide-toggle { - margin-bottom: 16px; - } - - mat-form-field { - margin-right: 15px; - } - - .slider-icon { - position: absolute; - transform: translateY(-3px); - } - - .block-title { - font-size: 20px; - font-weight: 400; - padding-top: 16px; - } - - .hover-cursor { - cursor: pointer; - } - } - - .security-toggle-group { - margin-bottom: 15px; + .toggle-group { margin-right: auto; } - .logs-label { - font-weight: 500; - margin-bottom: 10px; - } - - .statistics-block { - margin-bottom: 15px; - padding-left: 15px; - padding-top: 15px; - } - .first-capital { text-transform: capitalize; } - mat-panel-title { - display: block; - padding-top: 20px; - } - - mat-panel-title span { - display: block; - padding-left: 0; - padding-top: 5px; - } - - .tb-hint { - font-size: 13px; - color: rgba(0, 0, 0, .54); - width: fit-content; - cursor: pointer; - text-transform: none !important; - } - - .line-break { - width: 100%; - } - textarea { resize: none; } -} - -:host ::ng-deep { - .mat-tab-label-active { - color: white; - opacity: 1; - } - - .mat-tab-label, .mat-tab-label-active{ - min-width: 50px !important; - padding: 3px !important; - margin: 3px !important; - flex-grow: 1; - } - .mat-ink-bar { - height: 100%; - z-index: -10; - border-radius: 5px; + .saving-period { + flex: 1; } +} +:host ::ng-deep { .pointer-event { pointer-events: all; } - .mat-mdc-form-field-icon-suffix { - z-index: 100; + .toggle-group span { + padding: 0 25px; } - .security-toggle-group span { - padding: 0 25px; + .mat-mdc-form-field-icon-suffix { + color: #E0E0E0; + &:hover { + color: #9E9E9E; + } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts index a57bd6750e..bef0c2cc74 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts @@ -15,15 +15,11 @@ /// import { ChangeDetectorRef, Component, Input, OnInit } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { Router } from '@angular/router'; import { FormArray, FormBuilder, FormControl, FormGroup, - UntypedFormGroup, ValidationErrors, ValidatorFn, Validators @@ -41,79 +37,17 @@ import { Observable, of } from 'rxjs'; import { mergeMap } from 'rxjs/operators'; import { DeviceCredentials, DeviceCredentialsType } from '@shared/models/device.models'; import { NULL_UUID } from '@shared/models/id/has-uuid'; - -export enum StorageTypes { - MEMORY = 'memory', - FILE = 'file', - SQLITE = 'sqlite' -} - -export enum GatewayLogLevel { - none = 'NONE', - critical = 'CRITICAL', - error = 'ERROR', - warning = 'WARNING', - info = 'INFO', - debug = 'DEBUG' -} - -export enum LogSavingPeriod { - days = 'D', - hours = 'H', - minutes = 'M', - seconds = 'S' -} - -export enum LocalLogsConfigs { - service = 'service', - connector = 'connector', - converter = 'converter', - tb_connection = 'tb_connection', - storage = 'storage', - extension = 'extension' -} - -export const localLogsConfigLabels = new Map([ - [LocalLogsConfigs.service, 'Service'], - [LocalLogsConfigs.connector, 'Connector'], - [LocalLogsConfigs.converter, 'Converter'], - [LocalLogsConfigs.tb_connection, 'TB Connection'], - [LocalLogsConfigs.storage, 'Storage'], - [LocalLogsConfigs.extension, 'Extension'] -]); - -export const logSavingPeriodTranslations = new Map( - [ - [LogSavingPeriod.days, 'gateway.logs.days'], - [LogSavingPeriod.hours, 'gateway.logs.hours'], - [LogSavingPeriod.minutes, 'gateway.logs.minutes'], - [LogSavingPeriod.seconds, 'gateway.logs.seconds'] - ] -); - -export const storageTypesTranslations = new Map( - [ - [StorageTypes.MEMORY, 'gateway.storage-types.memory-storage'], - [StorageTypes.FILE, 'gateway.storage-types.file-storage'], - [StorageTypes.SQLITE, 'gateway.storage-types.sqlite'] - ] -); - -export enum SecurityTypes { - ACCESS_TOKEN = 'accessToken', - USERNAME_PASSWORD = 'usernamePassword', - TLS_ACCESS_TOKEN = 'tlsAccessToken', - TLS_PRIVATE_KEY = 'tlsPrivateKey' -} - -export const securityTypesTranslationsMap = new Map( - [ - [SecurityTypes.ACCESS_TOKEN, 'gateway.security-types.access-token'], - [SecurityTypes.USERNAME_PASSWORD, 'gateway.security-types.username-password'], - [SecurityTypes.TLS_ACCESS_TOKEN, 'gateway.security-types.tls-access-token'], - // [SecurityTypes.TLS_PRIVATE_KEY, 'gateway.security-types.tls-private-key'], - ] -); +import { + GatewayLogLevel, + GecurityTypesTranslationsMap, + LocalLogsConfigTranslateMap, + LocalLogsConfigs, + LogSavingPeriod, + LogSavingPeriodTranslations, + SecurityTypes, + StorageTypes, + StorageTypesTranslationMap +} from './gateway-widget.models'; @Component({ selector: 'tb-gateway-configuration', @@ -124,13 +58,16 @@ export class GatewayConfigurationComponent implements OnInit { gatewayConfigGroup: FormGroup; - storageTypes = storageTypesTranslations; + StorageTypes = StorageTypes; + storageTypes = Object.values(StorageTypes) as StorageTypes[]; + storageTypesTranslationMap = StorageTypesTranslationMap; - logSavingPeriods = logSavingPeriodTranslations; + logSavingPeriods = LogSavingPeriodTranslations; - localLogsConfigLabels = localLogsConfigLabels; + localLogsConfigs = Object.keys(LocalLogsConfigs) as LocalLogsConfigs[]; + localLogsConfigTranslateMap = LocalLogsConfigTranslateMap; - securityTypes = securityTypesTranslationsMap; + securityTypes = GecurityTypesTranslationsMap; gatewayLogLevel = Object.values(GatewayLogLevel); @@ -142,18 +79,13 @@ export class GatewayConfigurationComponent implements OnInit { logSelector: FormControl; - securityType: SecurityTypes; + private initialCredentials: DeviceCredentials; - initialCredentials: DeviceCredentials; - - - constructor(protected router: Router, - protected store: Store, - protected fb: FormBuilder, - protected attributeService: AttributeService, - protected deviceService: DeviceService, + constructor(private fb: FormBuilder, + private attributeService: AttributeService, + private deviceService: DeviceService, private cd: ChangeDetectorRef, - public dialog: MatDialog) { + private dialog: MatDialog) { } ngOnInit() { @@ -221,7 +153,7 @@ export class GatewayConfigurationComponent implements OnInit { type: ['remote', [Validators.required]], remote: this.fb.group({ enabled: [false], - logLevel: [GatewayLogLevel.info, [Validators.required]], + logLevel: [GatewayLogLevel.INFO, [Validators.required]], }), local: this.fb.group({}) }) @@ -231,7 +163,7 @@ export class GatewayConfigurationComponent implements OnInit { if (password && password !== '') { this.gatewayConfigGroup.get('thingsboard.security.username').setValidators([Validators.required]); } else { - this.gatewayConfigGroup.get('thingsboard.security.username').setValidators([]); + this.gatewayConfigGroup.get('thingsboard.security.username').clearValidators(); } this.gatewayConfigGroup.get('thingsboard.security.username').updateValueAndValidity({emitEvent: false}); }); @@ -258,10 +190,10 @@ export class GatewayConfigurationComponent implements OnInit { checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').setValidators([Validators.min(1), Validators.required]); } else { checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').clearValidators(); - checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').setErrors(null); checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').clearValidators(); - checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').setErrors(null); } + checkingDeviceActivityGroup.get('inactivityTimeoutSeconds').updateValueAndValidity({emitEvent: false}); + checkingDeviceActivityGroup.get('inactivityCheckPeriodSeconds').updateValueAndValidity({emitEvent: false}); }); this.gatewayConfigGroup.get('grpc.enabled').valueChanges.subscribe(value => { @@ -287,16 +219,14 @@ export class GatewayConfigurationComponent implements OnInit { securityGroup.get('caCert').addValidators([Validators.required]); securityGroup.get('caCert').updateValueAndValidity(); } else if (type === SecurityTypes.USERNAME_PASSWORD) { - securityGroup.addValidators([this.atLeastOneRequired(Validators.required, ['clientId', 'username'])]) - // securityGroup.get('password').addValidators([Validators.required]); - // securityGroup.get('password').updateValueAndValidity(); + securityGroup.addValidators([this.atLeastOneRequired(Validators.required, ['clientId', 'username'])]); } securityGroup.updateValueAndValidity(); }); - securityGroup.get('caCert').valueChanges.subscribe(_ => this.cd.detectChanges()); - securityGroup.get('privateKey').valueChanges.subscribe(_ => this.cd.detectChanges()); - securityGroup.get('cert').valueChanges.subscribe(_ => this.cd.detectChanges()); + securityGroup.get('caCert').valueChanges.subscribe(() => this.cd.detectChanges()); + securityGroup.get('privateKey').valueChanges.subscribe(() => this.cd.detectChanges()); + securityGroup.get('cert').valueChanges.subscribe(() => this.cd.detectChanges()); const storageGroup = this.gatewayConfigGroup.get('storage') as FormGroup; storageGroup.get('type').valueChanges.subscribe(type => { @@ -306,6 +236,8 @@ export class GatewayConfigurationComponent implements OnInit { [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]); storageGroup.get('max_records_count').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); + storageGroup.get('read_records_count').updateValueAndValidity({emitEvent: false}); + storageGroup.get('max_records_count').updateValueAndValidity({emitEvent: false}); } else if (type === StorageTypes.FILE) { storageGroup.get('data_folder_path').addValidators([Validators.required]); storageGroup.get('max_file_count').addValidators( @@ -314,20 +246,27 @@ export class GatewayConfigurationComponent implements OnInit { [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); storageGroup.get('max_records_per_file').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); + storageGroup.get('data_folder_path').updateValueAndValidity({emitEvent: false}); + storageGroup.get('max_file_count').updateValueAndValidity({emitEvent: false}); + storageGroup.get('max_read_records_count').updateValueAndValidity({emitEvent: false}); + storageGroup.get('max_records_per_file').updateValueAndValidity({emitEvent: false}); } else if (type === StorageTypes.SQLITE) { storageGroup.get('data_file_path').addValidators([Validators.required]); storageGroup.get('messages_ttl_check_in_hours').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); storageGroup.get('messages_ttl_in_days').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); + storageGroup.get('data_file_path').updateValueAndValidity({emitEvent: false}); + storageGroup.get('messages_ttl_check_in_hours').updateValueAndValidity({emitEvent: false}); + storageGroup.get('messages_ttl_in_days').updateValueAndValidity({emitEvent: false}); } }); this.fetchConfigAttribute(this.device); } - atLeastOneRequired(validator: ValidatorFn, controls: string[] = null) { - return (group: UntypedFormGroup): ValidationErrors | null => { + private atLeastOneRequired(validator: ValidatorFn, controls: string[] = null) { + return (group: FormGroup): ValidationErrors | null => { if (!controls) { controls = Object.keys(group.controls); } @@ -337,22 +276,10 @@ export class GatewayConfigurationComponent implements OnInit { }; } - updateSecurityValidators(value: SecurityTypes) { - this.gatewayConfigGroup.get('thingsboard.security.type').setValue(value, {emitEvent: true}); - this.gatewayConfigGroup.get('thingsboard.security.type').markAsDirty(); - } - - updateLogType(value: LocalLogsConfigs) { - this.logSelector.setValue(value); - } - - updateStorageType(value: StorageTypes) { - this.gatewayConfigGroup.get('storage.type').setValue(value, {emitEvent: true}); - this.gatewayConfigGroup.get('storage.type').markAsDirty(); - } - - fetchConfigAttribute(entityId: EntityId) { - if (entityId.id === NULL_UUID) return; + private fetchConfigAttribute(entityId: EntityId) { + if (entityId.id === NULL_UUID) { + return; + } this.attributeService.getEntityAttributes(entityId, AttributeScope.CLIENT_SCOPE, ['general_configuration', 'grpc_configuration', 'logs_configuration', 'storage_configuration', 'RemoteLoggingLevel']).pipe( mergeMap(attributes => attributes.length ? of(attributes) : this.attributeService.getEntityAttributes( @@ -397,24 +324,26 @@ export class GatewayConfigurationComponent implements OnInit { if (remoteLoggingLevel) { const remoteLogsFormGroup = this.gatewayConfigGroup.get('logs.remote'); remoteLogsFormGroup.patchValue({ - enabled: remoteLoggingLevel !== GatewayLogLevel.none, + enabled: remoteLoggingLevel !== GatewayLogLevel.NONE, logLevel: remoteLoggingLevel }, {emitEvent: false}); remoteLogsFormGroup.markAsPristine(); } this.cd.detectChanges(); } else { - this.checkAndFetchCredentials({}); + this.checkAndFetchCredentials(); } }); } - checkAndFetchCredentials(security): void { + private checkAndFetchCredentials(security: any = {}): void { if (security.type !== SecurityTypes.TLS_PRIVATE_KEY) { this.deviceService.getDeviceCredentials(this.device.id).subscribe(credentials => { this.initialCredentials = credentials; if (credentials.credentialsType === DeviceCredentialsType.ACCESS_TOKEN || security.type === SecurityTypes.TLS_ACCESS_TOKEN) { - this.gatewayConfigGroup.get('thingsboard.security.type').setValue(security.type === SecurityTypes.TLS_ACCESS_TOKEN? SecurityTypes.TLS_ACCESS_TOKEN : SecurityTypes.ACCESS_TOKEN); + this.gatewayConfigGroup.get('thingsboard.security.type').setValue(security.type === SecurityTypes.TLS_ACCESS_TOKEN + ? SecurityTypes.TLS_ACCESS_TOKEN + : SecurityTypes.ACCESS_TOKEN); this.gatewayConfigGroup.get('thingsboard.security.accessToken').setValue(credentials.credentialsId); if(security.type === SecurityTypes.TLS_ACCESS_TOKEN) { this.gatewayConfigGroup.get('thingsboard.security.caCert').setValue(security.caCert); @@ -432,7 +361,7 @@ export class GatewayConfigurationComponent implements OnInit { } } - logsToObj(logsConfig) { + private logsToObj(logsConfig: any) { const logsObject = { local: {} }; @@ -453,43 +382,42 @@ export class GatewayConfigurationComponent implements OnInit { return {local: logsObject, logFormat, dateFormat}; } - toggleRpcFields(enable: boolean) { + private toggleRpcFields(enable: boolean) { const grpcGroup = this.gatewayConfigGroup.get('grpc') as FormGroup; if (enable) { - grpcGroup.get('serverPort').enable(); - grpcGroup.get('keepAliveTimeMs').enable(); - grpcGroup.get('keepAliveTimeoutMs').enable(); - grpcGroup.get('keepalivePermitWithoutCalls').enable(); - grpcGroup.get('maxPingsWithoutData').enable(); - grpcGroup.get('minTimeBetweenPingsMs').enable(); - grpcGroup.get('minPingIntervalWithoutDataMs').enable(); + grpcGroup.get('serverPort').enable({emitEvent: false}); + grpcGroup.get('keepAliveTimeMs').enable({emitEvent: false}); + grpcGroup.get('keepAliveTimeoutMs').enable({emitEvent: false}); + grpcGroup.get('keepalivePermitWithoutCalls').enable({emitEvent: false}); + grpcGroup.get('maxPingsWithoutData').enable({emitEvent: false}); + grpcGroup.get('minTimeBetweenPingsMs').enable({emitEvent: false}); + grpcGroup.get('minPingIntervalWithoutDataMs').enable({emitEvent: false}); } else { - grpcGroup.get('serverPort').disable(); - grpcGroup.get('keepAliveTimeMs').disable(); - grpcGroup.get('keepAliveTimeoutMs').disable(); - grpcGroup.get('keepalivePermitWithoutCalls').disable(); - grpcGroup.get('maxPingsWithoutData').disable(); - grpcGroup.get('minTimeBetweenPingsMs').disable(); - grpcGroup.get('minPingIntervalWithoutDataMs').disable(); + grpcGroup.get('serverPort').disable({emitEvent: false}); + grpcGroup.get('keepAliveTimeMs').disable({emitEvent: false}); + grpcGroup.get('keepAliveTimeoutMs').disable({emitEvent: false}); + grpcGroup.get('keepalivePermitWithoutCalls').disable({emitEvent: false}); + grpcGroup.get('maxPingsWithoutData').disable({emitEvent: false}); + grpcGroup.get('minTimeBetweenPingsMs').disable({emitEvent: false}); + grpcGroup.get('minPingIntervalWithoutDataMs').disable({emitEvent: false}); } } - addCommand(command?): void { - const data = command || {}; + addCommand(command: any = {}): void { const commandsFormArray = this.commandFormArray(); const commandFormGroup = this.fb.group({ - attributeOnGateway: [data.attributeOnGateway || null, [Validators.required]], - command: [data.command || null, [Validators.required]], - timeout: [data.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + attributeOnGateway: [command.attributeOnGateway || null, [Validators.required]], + command: [command.command || null, [Validators.required]], + timeout: [command.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], }); commandsFormArray.push(commandFormGroup); } - addLocalLogConfig(name, config): void { + private addLocalLogConfig(name: string, config: any): void { const localLogsFormGroup = this.gatewayConfigGroup.get('logs.local') as FormGroup; const configGroup = this.fb.group({ - logLevel: [config.logLevel || GatewayLogLevel.info, [Validators.required]], + logLevel: [config.logLevel || GatewayLogLevel.INFO, [Validators.required]], filePath: [config.filePath || './logs', [Validators.required]], backupCount: [config.backupCount || 7, [Validators.required, Validators.min(0)]], savingTime: [config.savingTime || 3, [Validators.required, Validators.min(0)]], @@ -507,12 +435,14 @@ export class GatewayConfigurationComponent implements OnInit { } removeCommandControl(index: number, event: any): void { - if (event.pointerType === '') return; + if (event.pointerType === '') { + return; + } this.commandFormArray().removeAt(index); this.gatewayConfigGroup.markAsDirty(); } - removeAllSecurityValidators(): void { + private removeAllSecurityValidators(): void { const securityGroup = this.gatewayConfigGroup.get('thingsboard.security') as FormGroup; securityGroup.clearValidators(); for (const controlsKey in securityGroup.controls) { @@ -524,7 +454,7 @@ export class GatewayConfigurationComponent implements OnInit { } } - removeAllStorageValidators(): void { + private removeAllStorageValidators(): void { const storageGroup = this.gatewayConfigGroup.get('storage') as FormGroup; for (const storageKey in storageGroup.controls) { if (storageKey !== 'type') { @@ -535,7 +465,7 @@ export class GatewayConfigurationComponent implements OnInit { } } - removeEmpty(obj) { + private removeEmpty(obj: any) { return Object.fromEntries( Object.entries(obj) .filter(([_, v]) => v != null) @@ -543,7 +473,7 @@ export class GatewayConfigurationComponent implements OnInit { ); } - generateLogsFile(logsObj) { + private generateLogsFile(logsObj: any) { const logAttrObj = { version: 1, disable_existing_loggers: false, @@ -591,7 +521,7 @@ export class GatewayConfigurationComponent implements OnInit { return logAttrObj; } - createHandlerObj(logObj, key) { + private createHandlerObj(logObj: any, key: string) { return { class: 'thingsboard_gateway.tb_utility.tb_handler.TimedRotatingFileHandler', formatter: 'LogFormatter', @@ -603,7 +533,7 @@ export class GatewayConfigurationComponent implements OnInit { }; } - createLoggerObj(logObj, key) { + private createLoggerObj(logObj: any, key: string) { return { handlers: [`${key}Handler`, 'consoleHandler'], level: logObj.logLevel, @@ -617,7 +547,7 @@ export class GatewayConfigurationComponent implements OnInit { const attributes = []; attributes.push({ key: 'RemoteLoggingLevel', - value: value.logs.remote.enabled ? value.logs.remote.logLevel : GatewayLogLevel.none + value: value.logs.remote.enabled ? value.logs.remote.logLevel : GatewayLogLevel.NONE }); delete value.connectors; attributes.push({ @@ -642,18 +572,18 @@ export class GatewayConfigurationComponent implements OnInit { this.attributeService.saveEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, attributes).subscribe(_ => { - this.updateCredentials(value.thingsboard.security).subscribe(_ => { + this.updateCredentials(value.thingsboard.security).subscribe(() => { if (this.dialogRef) { this.dialogRef.close(); } else { this.gatewayConfigGroup.markAsPristine(); this.cd.detectChanges(); } - }) + }); }); } - updateCredentials(securityConfig): Observable { + private updateCredentials(securityConfig: any): Observable { let updateCredentials = false; let newCredentials = {}; if (securityConfig.type === SecurityTypes.USERNAME_PASSWORD) { @@ -661,14 +591,23 @@ export class GatewayConfigurationComponent implements OnInit { updateCredentials = true; } else { const parsedCredentials = JSON.parse(this.initialCredentials.credentialsValue); - updateCredentials = !(parsedCredentials.clientId === securityConfig.clientId && parsedCredentials.userName === securityConfig.username && parsedCredentials.password === securityConfig.password); + updateCredentials = !( + parsedCredentials.clientId === securityConfig.clientId && + parsedCredentials.userName === securityConfig.username && + parsedCredentials.password === securityConfig.password); } if (updateCredentials) { - let credentialsValue: { clientId?, userName?, password? } = {}; + const credentialsValue: { clientId?: string; userName?: string; password?: string } = {}; const credentialsType = DeviceCredentialsType.MQTT_BASIC; - if (securityConfig.clientId) credentialsValue.clientId = securityConfig.clientId; - if (securityConfig.username) credentialsValue.userName = securityConfig.username; - if (securityConfig.password) credentialsValue.password = securityConfig.password; + if (securityConfig.clientId) { + credentialsValue.clientId = securityConfig.clientId; + } + if (securityConfig.username) { + credentialsValue.userName = securityConfig.username; + } + if (securityConfig.password) { + credentialsValue.password = securityConfig.password; + } newCredentials = { credentialsType, credentialsValue: JSON.stringify(credentialsValue) @@ -684,12 +623,12 @@ export class GatewayConfigurationComponent implements OnInit { newCredentials = { credentialsType: DeviceCredentialsType.ACCESS_TOKEN, credentialsId: securityConfig.accessToken - } + }; } } if (updateCredentials) { - return this.deviceService.saveDeviceCredentials({...this.initialCredentials,...newCredentials}) + return this.deviceService.saveDeviceCredentials({...this.initialCredentials,...newCredentials}); } return of(null); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index 6e4178fccd..9e852c0fcb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -15,82 +15,102 @@ limitations under the License. --> -
-
- - -

{{ 'gateway.connectors' | translate }}

- - -
- - - - {{ 'gateway.connectors-table-enabled' | translate }} - - - - - - - - {{ 'gateway.connectors-table-name' | translate }} - - {{ attribute.key }} - - - - - {{ 'gateway.connectors-table-type' | translate }} - - - {{ returnType(attribute) }} - - - - - {{ 'gateway.configuration' | translate }} - - -
{{isConnectorSynced(attribute)?'sync' : 'out of sync'}}
-
-
- - - {{ 'gateway.connectors-table-status' | translate }} - - - - - - - - {{ 'gateway.connectors-table-actions' | translate }} - - -
+
+
+ +

{{ 'gateway.connectors' | translate }}

+ + +
+
+ + + {{ 'gateway.connectors-table-enabled' | translate }} + + + + + + + + {{ 'gateway.connectors-table-name' | translate }} + + {{ attribute.key }} + + + + + {{ 'gateway.connectors-table-type' | translate }} + + + {{ returnType(attribute) }} + + + + + {{ 'gateway.configuration' | translate }} + + +
+ {{ isConnectorSynced(attribute) ? 'sync' : 'out of sync' }} +
+
+
+ + + {{ 'gateway.connectors-table-status' | translate }} + + + + + + + + {{ 'gateway.connectors-table-actions' | translate }} + + +
+ + + +
+
+ + -
-
- - - - - - -
-
-
- - -
- -
-
- - - {{ 'gateway.connectors-table-name' | translate }} - - - - {{ 'gateway.connectors-table-type' | translate }} - - {{type.value}} - - - - {{ 'gateway.connectors-table-key' | translate }} - - - - {{ 'gateway.connectors-table-class' | translate }} - - - - gateway.remote-logging-level - - {{logLevel}} - - - - - - -
- -
-
-
-
-
+ +
+ + + + + + +
+
+ + {{ 'gateway.connectors-table-name' | translate }} + + + + {{ 'gateway.connectors-table-type' | translate }} + + {{ type.value }} + + + + {{ 'gateway.connectors-table-key' | translate }} + + + + {{ 'gateway.connectors-table-class' | translate }} + + + + gateway.remote-logging-level + + {{ logLevel }} + + +
+
+ + +
+ +
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss index 1edb40967c..f4326f6abc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.scss @@ -13,6 +13,8 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +@import '../../../../../../../scss/constants'; + :host { width: 100%; height: 100%; @@ -21,25 +23,24 @@ padding: 0; .connector-container { + height: 100%; width: 100%; + flex-direction: row; + @media #{$mat-lt-lg} { + flex-direction: column; + } - & > mat-card, & > div { - min-width: calc(50% - 15px); + .table-container { + overflow: auto; + min-height: 35vh; } - mat-card { - margin: 10px; - padding: 10px; - max-width: 100%; + .flex { + flex: 1; } - } - .tb-entity-table { - .tb-entity-table-content { - width: 100%; - height: 100%; - background: #fff; - overflow: hidden; + .input-container { + height: auto; } } @@ -48,43 +49,28 @@ color: rgba(0, 0, 0, .87) !important; } - .mat-mdc-form-field { - flex-grow: 1; - } - - mat-card { - padding-left: 10px; - background: transparent; - } - - .mat-card-selected { - background-color: rgba(48, 86, 128, 0.1); - } - .mat-mdc-slide-toggle { - margin: 15px; + margin: 0 8px; } - .status-block { + .status { text-align: center; border-radius: 16px; font-weight: 500; width: fit-content; padding: 5px 15px; + &-sync { + background: rgba(25, 128, 56, .06); + color: rgb(25, 128, 56); + } + &-unsync { + background: rgba(203, 37, 48, .06); + color: rgb(203, 37, 48); + } } - .status-sync { - background: rgba(25, 128, 56, .06); - color: rgb(25, 128, 56); - } - - .status-unsync { - background: rgba(203, 37, 48, .06); - color: rgb(203, 37, 48); - } - - .action-btns { - margin: 10px 10px 0; + .action-button { + margin: 0 15px; } mat-row { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts index 14410c3b64..e1688357f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.ts @@ -17,14 +17,11 @@ import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, Input, NgZone, ViewChild } from '@angular/core'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; -import { Router } from '@angular/router'; import { FormBuilder, FormGroup, UntypedFormControl, ValidatorFn, Validators } from '@angular/forms'; import { EntityId } from '@shared/models/id/entity-id'; -import { MatDialog } from '@angular/material/dialog'; import { AttributeService } from '@core/http/attribute.service'; -import { DeviceService } from '@core/http/device.service'; import { TranslateService } from '@ngx-translate/core'; -import { forkJoin } from 'rxjs'; +import { forkJoin, Observable } from 'rxjs'; import { AttributeData, AttributeScope } from '@shared/models/telemetry/telemetry.models'; import { PageComponent } from '@shared/components/page.component'; import { PageLink } from '@shared/models/page/page-link'; @@ -33,47 +30,20 @@ import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { MatSort } from '@angular/material/sort'; import { TelemetryWebsocketService } from '@core/ws/telemetry-websocket.service'; import { MatTableDataSource } from '@angular/material/table'; -import { GatewayLogLevel } from '@home/components/widget/lib/gateway/gateway-configuration.component'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { DialogService } from '@core/services/dialog.service'; import { WidgetContext } from '@home/models/widget-component.models'; -import { deepClone } from '@core/utils'; +import { camelCase, deepClone, isString } from '@core/utils'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { IWidgetSubscription, WidgetSubscriptionOptions } from '@core/api/widget-api.models'; import { DatasourceType, widgetType } from '@shared/models/widget.models'; import { UtilsService } from '@core/services/utils.service'; import { EntityType } from '@shared/models/entity-type.models'; - - -export interface gatewayConnector { - name: string; - type: string; - configuration?: string; - configurationJson: string; - logLevel: string; - key?: string; -} - - -export const GatewayConnectorDefaultTypesTranslates = new Map([ - ['mqtt', 'MQTT'], - ['modbus', 'MODBUS'], - ['grpc', 'GRPC'], - ['opcua', 'OPCUA'], - ['opcua_asyncio', 'OPCUA ASYNCIO'], - ['ble', 'BLE'], - ['request', 'REQUEST'], - ['can', 'CAN'], - ['bacnet', 'BACNET'], - ['odbc', 'ODBC'], - ['rest', 'REST'], - ['snmp', 'SNMP'], - ['ftp', 'FTP'], - ['socket', 'SOCKET'], - ['xmpp', 'XMPP'], - ['ocpp', 'OCCP'], - ['custom', 'CUSTOM'] -]); +import { + GatewayConnector, + GatewayConnectorDefaultTypesTranslates, + GatewayLogLevel +} from './gateway-widget.models'; @Component({ selector: 'tb-gateway-connector', @@ -84,12 +54,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie pageLink: PageLink; - attributeDataSource: AttributeDatasource; - - inactiveConnectorsDataSource: AttributeDatasource; - - serverDataSource: AttributeDatasource; - dataSource: MatTableDataSource; displayedColumns = ['enabled', 'key', 'type', 'syncStatus', 'errors', 'actions']; @@ -107,27 +71,29 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie connectorForm: FormGroup; - viewsInited = false; - textSearchMode: boolean; activeConnectors: Array; - inactiveConnectors: Array; + gatewayLogLevel = Object.values(GatewayLogLevel); - InitialActiveConnectors: Array; + private inactiveConnectors: Array; - gatewayLogLevel = Object.values(GatewayLogLevel); + private attributeDataSource: AttributeDatasource; + + private inactiveConnectorsDataSource: AttributeDatasource; - activeData: Array = []; + private serverDataSource: AttributeDatasource; - inactiveData: Array = []; + private activeData: Array = []; - sharedAttributeData: Array = []; + private inactiveData: Array = []; - initialConnector: gatewayConnector; + private sharedAttributeData: Array = []; - subscriptionOptions: WidgetSubscriptionOptions = { + private initialConnector: GatewayConnector; + + private subscriptionOptions: WidgetSubscriptionOptions = { callbacks: { onDataUpdated: () => this.ctx.ngZone.run(() => { this.onDataUpdated(); @@ -138,20 +104,17 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } }; - subscription: IWidgetSubscription; + private subscription: IWidgetSubscription; - constructor(protected router: Router, - protected store: Store, - protected fb: FormBuilder, - protected translate: TranslateService, - protected attributeService: AttributeService, - protected deviceService: DeviceService, - protected dialogService: DialogService, + constructor(protected store: Store, + private fb: FormBuilder, + private translate: TranslateService, + private attributeService: AttributeService, + private dialogService: DialogService, private telemetryWsService: TelemetryWebsocketService, private zone: NgZone, private utils: UtilsService, - private cd: ChangeDetectorRef, - public dialog: MatDialog) { + private cd: ChangeDetectorRef) { super(store); const sortOrder: SortOrder = {property: 'key', direction: Direction.ASC}; this.pageLink = new PageLink(1000, 0, null, sortOrder); @@ -186,16 +149,21 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie return data[sortHeaderId] || data.value[sortHeaderId]; }; - this.viewsInited = true; if (this.device) { - if (this.device.id === NULL_UUID) return; - forkJoin(this.attributeService.getEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, ['active_connectors']), - this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors'])).subscribe(attributes => { + if (this.device.id === NULL_UUID) { + return; + } + forkJoin([ + this.attributeService.getEntityAttributes(this.device, AttributeScope.SHARED_SCOPE, ['active_connectors']), + this.attributeService.getEntityAttributes(this.device, AttributeScope.SERVER_SCOPE, ['inactive_connectors']) + ]).subscribe(attributes => { if (attributes.length) { this.activeConnectors = attributes[0].length ? attributes[0][0].value : []; - this.activeConnectors = typeof this.activeConnectors === 'string' ? JSON.parse(this.activeConnectors) : this.activeConnectors; + this.activeConnectors = isString(this.activeConnectors) ? JSON.parse(this.activeConnectors as any) : this.activeConnectors; this.inactiveConnectors = attributes[1].length ? attributes[1][0].value : []; - this.inactiveConnectors = typeof this.inactiveConnectors === 'string' ? JSON.parse(this.inactiveConnectors) : this.inactiveConnectors; + this.inactiveConnectors = isString(this.inactiveConnectors) + ? JSON.parse(this.inactiveConnectors as any) + : this.inactiveConnectors; this.updateData(true); } else { this.activeConnectors = []; @@ -206,7 +174,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } } - uniqNameRequired(): ValidatorFn { + private uniqNameRequired(): ValidatorFn { return (c: UntypedFormControl) => { const newName = c.value.trim().toLowerCase(); const found = this.dataSource.data.find((connectorAttr) => { @@ -229,7 +197,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie saveConnector(): void { const value = this.connectorForm.value; - value.configuration = this.camelize(value.name) + '.json'; + value.configuration = camelCase(value.name) + '.json'; if (value.type !== 'grpc') { delete value.key; } @@ -242,7 +210,9 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie value }]; const attributesToDelete = []; - const scope = (this.initialConnector && this.activeConnectors.includes(this.initialConnector.name)) ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; + const scope = (this.initialConnector && this.activeConnectors.includes(this.initialConnector.name)) + ? AttributeScope.SHARED_SCOPE + : AttributeScope.SERVER_SCOPE; let updateActiveConnectors = false; if (this.initialConnector && this.initialConnector.name !== value.name) { attributesToDelete.push({key: this.initialConnector.name}); @@ -256,19 +226,19 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.inactiveConnectors.splice(inactiveIndex, 1); } } - if (!this.activeConnectors.includes(value.name) && scope == AttributeScope.SHARED_SCOPE) { + if (!this.activeConnectors.includes(value.name) && scope === AttributeScope.SHARED_SCOPE) { this.activeConnectors.push(value.name); updateActiveConnectors = true; } - if (!this.inactiveConnectors.includes(value.name) && scope == AttributeScope.SERVER_SCOPE) { + if (!this.inactiveConnectors.includes(value.name) && scope === AttributeScope.SERVER_SCOPE) { this.inactiveConnectors.push(value.name); updateActiveConnectors = true; } const tasks = [this.attributeService.saveEntityAttributes(this.device, scope, attributesToSave)]; if (updateActiveConnectors) { tasks.push(this.attributeService.saveEntityAttributes(this.device, scope, [{ - key: scope == AttributeScope.SHARED_SCOPE ? 'active_connectors' : 'inactive_connectors', - value: scope == AttributeScope.SHARED_SCOPE ? this.activeConnectors : this.inactiveConnectors + key: scope === AttributeScope.SHARED_SCOPE ? 'active_connectors' : 'inactive_connectors', + value: scope === AttributeScope.SHARED_SCOPE ? this.activeConnectors : this.inactiveConnectors }])); } @@ -282,7 +252,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } - updateData(reload: boolean = false) { + private updateData(reload: boolean = false) { this.pageLink.sortOrder.property = this.sort.active; this.pageLink.sortOrder.direction = Direction[this.sort.direction.toUpperCase()]; this.attributeDataSource.loadAttributes(this.device, AttributeScope.CLIENT_SCOPE, this.pageLink, reload).subscribe(data => { @@ -301,26 +271,30 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } isConnectorSynced(attribute: AttributeData) { - const connectorData = attribute.value; - if (!connectorData.ts) return false; + const connectorData = attribute.value; + if (!connectorData.ts) { + return false; + } const clientIndex = this.activeData.findIndex(data => { - const sharedData = data.value; + const sharedData = data.value; return sharedData.name === connectorData.name; - }) - if (clientIndex == -1) return false; + }); + if (clientIndex === -1) { + return false; + } const sharedIndex = this.sharedAttributeData.findIndex(data => { - const sharedData = data.value; + const sharedData = data.value; return sharedData.name === connectorData.name && sharedData.ts && sharedData.ts <= connectorData.ts; - }) + }); return sharedIndex !== -1; } - combineData() { + private combineData() { this.dataSource.data = [...this.activeData, ...this.inactiveData, ...this.sharedAttributeData].filter((item, index, self) => index === self.findIndex((t) => t.key === item.key) - ).map(attribute=>{ + ).map(attribute => { attribute.value = typeof attribute.value === 'string' ? JSON.parse(attribute.value) : attribute.value; - return attribute + return attribute; }); } @@ -330,14 +304,13 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } this.nameInput.nativeElement.focus(); this.clearOutConnectorForm(); - } - clearOutConnectorForm(): void { + private clearOutConnectorForm(): void { this.connectorForm.setValue({ name: '', type: 'mqtt', - logLevel: GatewayLogLevel.info, + logLevel: GatewayLogLevel.INFO, key: 'auto', class: '', configuration: '', @@ -347,7 +320,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.connectorForm.markAsPristine(); } - selectConnector(attribute): void { + selectConnector(attribute: AttributeData): void { if (this.connectorForm.disabled) { this.connectorForm.enable(); } @@ -363,8 +336,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.connectorForm.markAsPristine(); } - isSameConnector(attribute): boolean { - if (!this.initialConnector) return false; + isSameConnector(attribute: AttributeData): boolean { + if (!this.initialConnector) { + return false; + } const connector = attribute.value; return this.initialConnector.name === connector.name; } @@ -378,12 +353,11 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie verticalPosition: 'top', horizontalPosition: 'right', target: 'dashboardRoot', - // panelClass: this.widgetNamespace, forceDismiss: true })); } - returnType(attribute) { + returnType(attribute: AttributeData): string { const value = attribute.value; return this.gatewayConnectorDefaultTypes.get(value.type); } @@ -396,8 +370,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie const content = `All connector data will be deleted.`; this.dialogService.confirm(title, content, 'Cancel', 'Delete').subscribe(result => { if (result) { - const tasks = []; - const scope = (this.initialConnector && this.activeConnectors.includes(this.initialConnector.name)) ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; + const tasks: Array> = []; + const scope = (this.initialConnector && this.activeConnectors.includes(this.initialConnector.name)) + ? AttributeScope.SHARED_SCOPE + : AttributeScope.SERVER_SCOPE; tasks.push(this.attributeService.deleteEntityAttributes(this.device, scope, [attribute])); const activeIndex = this.activeConnectors.indexOf(attribute.key); const inactiveIndex = this.inactiveConnectors.indexOf(attribute.key); @@ -408,10 +384,10 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie this.inactiveConnectors.splice(inactiveIndex, 1); } tasks.push(this.attributeService.saveEntityAttributes(this.device, scope, [{ - key: scope == AttributeScope.SHARED_SCOPE ? 'active_connectors' : 'inactive_connectors', - value: scope == AttributeScope.SHARED_SCOPE ? this.activeConnectors : this.inactiveConnectors + key: scope === AttributeScope.SHARED_SCOPE ? 'active_connectors' : 'inactive_connectors', + value: scope === AttributeScope.SHARED_SCOPE ? this.activeConnectors : this.inactiveConnectors }])); - forkJoin(tasks).subscribe(_ => { + forkJoin(tasks).subscribe(() => { if (this.initialConnector ? this.initialConnector.name === attribute.key : true) { this.clearOutConnectorForm(); this.cd.detectChanges(); @@ -423,10 +399,6 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } - camelize(str): string { - return str.toLowerCase().replace(/\s+/g, '_'); - } - connectorLogs(attribute: AttributeData, $event: Event): void { if ($event) { $event.stopPropagation(); @@ -448,7 +420,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie } - enableConnector(attribute): void { + enableConnector(attribute: AttributeData): void { const wasEnabled = this.activeConnectors.includes(attribute.key); const scopeOld = wasEnabled ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; const scopeNew = !wasEnabled ? AttributeScope.SHARED_SCOPE : AttributeScope.SERVER_SCOPE; @@ -475,7 +447,7 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie }); } - onDataUpdateError(e: any) { + private onDataUpdateError(e: any) { const exceptionData = this.utils.parseException(e); let errorText = exceptionData.name; if (exceptionData.message) { @@ -484,11 +456,11 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie console.error(errorText); } - onDataUpdated() { + private onDataUpdated() { this.cd.detectChanges(); } - generateSubscription() { + private generateSubscription() { if (this.subscription) { this.subscription.unsubscribe(); } @@ -497,21 +469,23 @@ export class GatewayConnectorComponent extends PageComponent implements AfterVie type: DatasourceType.entity, entityType: EntityType.DEVICE, entityId: this.device.id, - entityName: "Gateway", + entityName: 'Gateway', timeseries: [] }]; this.dataSource.data.forEach(value => { - subscriptionInfo[0].timeseries.push({name: `${value.key}_ERRORS_COUNT`, label: `${value.key}_ERRORS_COUNT`}) - }) - this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.latest, subscriptionInfo,this.subscriptionOptions, false, true).subscribe(subscription => { + subscriptionInfo[0].timeseries.push({name: `${value.key}_ERRORS_COUNT`, label: `${value.key}_ERRORS_COUNT`}); + }); + this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.latest, subscriptionInfo, this.subscriptionOptions, + false, true).subscribe(subscription => { this.subscription = subscription; }); } } - getErrorsCount(attribute) { + getErrorsCount(attribute: AttributeData): string { const connectorName = attribute.key; - const connector = this.subscription && this.subscription.data.find(data=>data && data.dataKey.name === `${connectorName}_ERRORS_COUNT`); - return (connector && this.activeConnectors.includes(connectorName))? connector.data[0][1]: 'Inactive'; + const connector = this.subscription && this.subscription.data + .find(data => data && data.dataKey.name === `${connectorName}_ERRORS_COUNT`); + return (connector && this.activeConnectors.includes(connectorName)) ? connector.data[0][1] : 'Inactive'; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html index bdf7d0d16e..973b3e02b7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html @@ -18,43 +18,39 @@ - Created time + {{ 'widgets.gateway.created-time' | translate }} - {{ attribute.ts | date:'yyyy-MM-dd HH:mm:ss'}} + {{ attribute.ts | date:'yyyy-MM-dd HH:mm:ss' }} - Status + {{ 'widgets.gateway.status' | translate }} - {{ attribute.status }} + {{ attribute.status }} - Message - + {{ 'widgets.gateway.message' | translate }} + {{ attribute.message }} - - + +
{{'attribute.no-telemetry-text' | translate}} + fxFlex fxLayoutAlign="center center" + class="no-data-found">{{ 'attribute.no-telemetry-text' | translate }} - diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.ts index f724e9dff9..6e0f20bdc3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.ts @@ -14,55 +14,27 @@ /// limitations under the License. /// -import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { Router } from '@angular/router'; -import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { AttributeService } from '@core/http/attribute.service'; -import { DeviceService } from '@core/http/device.service'; -import { TranslateService } from '@ngx-translate/core'; -import { AttributeData, DataKeyType } from '@shared/models/telemetry/telemetry.models'; -import { PageComponent } from '@shared/components/page.component'; +import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core'; +import { MatDialogRef } from '@angular/material/dialog'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { PageLink } from '@shared/models/page/page-link'; -import { AttributeDatasource } from "@home/models/datasource/attribute-datasource"; -import { Direction, SortOrder } from "@shared/models/page/sort-order"; +import { Direction, SortOrder } from '@shared/models/page/sort-order'; import { MatSort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; -import { GatewayLogLevel } from '@home/components/widget/lib/gateway/gateway-configuration.component'; -import { DialogService } from '@core/services/dialog.service'; import { WidgetContext } from '@home/models/widget-component.models'; import { MatPaginator } from '@angular/material/paginator'; - - -export interface GatewayConnector { - name: string; - type: string; - configuration?: string; - configurationJson: string; - logLevel: string; - key?: string; -} - -export interface LogLink { - name: string; - key: string; - filterFn?: Function; -} +import { GatewayLogData, GatewayStatus, LogLink } from './gateway-widget.models'; @Component({ selector: 'tb-gateway-logs', templateUrl: './gateway-logs.component.html', styleUrls: ['./gateway-logs.component.scss'] }) -export class GatewayLogsComponent extends PageComponent implements AfterViewInit { +export class GatewayLogsComponent implements AfterViewInit { pageLink: PageLink; - attributeDataSource: AttributeDatasource; - - dataSource: MatTableDataSource + dataSource: MatTableDataSource; displayedColumns = ['ts', 'status', 'message']; @@ -76,63 +48,39 @@ export class GatewayLogsComponent extends PageComponent implements AfterViewInit @ViewChild(MatSort) sort: MatSort; @ViewChild(MatPaginator) paginator: MatPaginator; - connectorForm: FormGroup; - - viewsInited = false; - textSearchMode: boolean; - activeConnectors: Array; - - inactiveConnectors: Array; - - InitialActiveConnectors: Array; - - gatewayLogLevel = Object.values(GatewayLogLevel); - logLinks: Array; - initialConnector: GatewayConnector; - activeLink: LogLink; gatewayLogLinks: Array = [ { - name: "General", - key: "LOGS" + name: 'General', + key: 'LOGS' }, { - name: "Service", - key: "SERVICE_LOGS" + name: 'Service', + key: 'SERVICE_LOGS' }, { - name: "Connection", - key: "CONNECTION_LOGS" + name: 'Connection', + key: 'CONNECTION_LOGS' }, { - name: "Storage", - key: "STORAGE_LOGS" + name: 'Storage', + key: 'STORAGE_LOGS' }, { key: 'EXTENSIONS_LOGS', - name: "Extension" - }] - - - constructor(protected router: Router, - protected store: Store, - protected fb: FormBuilder, - protected translate: TranslateService, - protected attributeService: AttributeService, - protected deviceService: DeviceService, - protected dialogService: DialogService, - public dialog: MatDialog) { - super(store); + name: 'Extension' + }]; + + + constructor() { const sortOrder: SortOrder = {property: 'ts', direction: Direction.DESC}; this.pageLink = new PageLink(10, 0, null, sortOrder); - this.dataSource = new MatTableDataSource([]); - + this.dataSource = new MatTableDataSource([]); } - ngAfterViewInit() { this.dataSource.sort = this.sort; this.dataSource.paginator = this.paginator; @@ -140,22 +88,18 @@ export class GatewayLogsComponent extends PageComponent implements AfterViewInit this.ctx.defaultSubscription.options.timeWindowConfig = timewindow; this.ctx.defaultSubscription.updateDataSubscriptions(); return timewindow; - } + }; if (this.ctx.settings.isConnectorLog && this.ctx.settings.connectorLogState) { const connector = this.ctx.stateController.getStateParams()[this.ctx.settings.connectorLogState]; this.logLinks = [{ key: `${connector.key}_LOGS`, - name: "Connector", - filterFn: (attrData)=>{ - return !attrData.message.includes(`_converter.py`) - } - },{ + name: 'Connector', + filterFn: (attrData) => !attrData.message.includes(`_converter.py`) + }, { key: `${connector.key}_LOGS`, - name: "Converter", - filterFn: (attrData)=>{ - return attrData.message.includes(`_converter.py`) - } - }] + name: 'Converter', + filterFn: (attrData) => attrData.message.includes(`_converter.py`) + }]; } else { this.logLinks = this.gatewayLogLinks; } @@ -164,20 +108,20 @@ export class GatewayLogsComponent extends PageComponent implements AfterViewInit } - updateData(sort?) { + private updateData() { if (this.ctx.defaultSubscription.data.length && this.ctx.defaultSubscription.data[0]) { let attrData = this.ctx.defaultSubscription.data[0].data.map(data => { - let result = { + const result = { ts: data[0], key: this.activeLink.key, message: /\[(.*)/.exec(data[1])[0], - status: 'INVALID LOG FORMAT' + status: 'INVALID LOG FORMAT' as GatewayStatus }; try { - result.status= data[1].match(/\|(\w+)\|/)[1]; + result.status = data[1].match(/\|(\w+)\|/)[1]; } catch (e) { - result.status = 'INVALID LOG FORMAT' + result.status = 'INVALID LOG FORMAT' as GatewayStatus; } return result; @@ -186,39 +130,35 @@ export class GatewayLogsComponent extends PageComponent implements AfterViewInit attrData = attrData.filter(data => this.activeLink.filterFn(data)); } this.dataSource.data = attrData; - if (sort) { - this.dataSource.sortData(this.dataSource.data, this.sort); - } } } - onTabChanged(link) { + onTabChanged(link: LogLink) { this.activeLink = link; this.changeSubscription(); } - statusClass(status) { + statusClass(status: GatewayStatus): string { switch (status) { - case GatewayLogLevel.debug: - return "status status-debug"; - case GatewayLogLevel.warning: - return "status status-warning"; - case GatewayLogLevel.error: - case "EXCEPTION": - return "status status-error"; - case GatewayLogLevel.info: + case GatewayStatus.DEBUG: + return 'status status-debug'; + case GatewayStatus.WARNING: + return 'status status-warning'; + case GatewayStatus.ERROR: + case GatewayStatus.EXCEPTION: + return 'status status-error'; default: - return "status status-info"; + return 'status status-info'; } } - statusClassMsg(status) { - if (status === "EXCEPTION") { + statusClassMsg(status?: GatewayStatus): string { + if (status === GatewayStatus.EXCEPTION) { return 'msg-status-exception'; } } - changeSubscription() { + private changeSubscription() { if (this.ctx.datasources && this.ctx.datasources[0].entity && this.ctx.defaultSubscription.options.datasources) { this.ctx.defaultSubscription.options.datasources[0].dataKeys = [{ name: this.activeLink.key, @@ -229,8 +169,7 @@ export class GatewayLogsComponent extends PageComponent implements AfterViewInit this.ctx.defaultSubscription.updateDataSubscriptions(); this.ctx.defaultSubscription.callbacks.onDataUpdated = () => { this.updateData(); - } - + }; } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.html index 7a66cfd4fb..adb7d0b197 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.html @@ -15,43 +15,38 @@ limitations under the License. --> -
- - warning -

gateway.configuration-delete-dialog-header

- - -
-
-
- - - gateway.configuration-delete-dialog-input - - - {{'gateway.configuration-delete-dialog-input-required' | translate }} - - -
-
-
- - -
-
+ + warning +

gateway.configuration-delete-dialog-header

+ + +
+
+ + + gateway.configuration-delete-dialog-input + + + {{ 'gateway.configuration-delete-dialog-input-required' | translate }} + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.ts index d5274eef97..68c19d83a5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-remote-configuration-dialog.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, OnInit } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -31,11 +31,10 @@ export interface GatewayRemoteConfigurationDialogData { templateUrl: './gateway-remote-configuration-dialog.html' }) -export class GatewayRemoteConfigurationDialogComponent extends DialogComponent implements OnInit { +export class GatewayRemoteConfigurationDialogComponent extends + DialogComponent{ gatewayName: string; - gatewayControl: FormControl; constructor(protected store: Store, @@ -45,10 +44,7 @@ export class GatewayRemoteConfigurationDialogComponent extends DialogComponent
- - {{'gateway.statistics.command' | translate}} - - - {{command}} - - - - - - {{'gateway.statistics.timeout-ms' | translate}} - - - {{'gateway.statistics.timeout-min' | translate }} - - - - {{'widget-config.datasource-parameters' | translate}} - - edit - - - + + + {{ 'gateway.statistics.command' | translate }} + + + {{ command }} + + + + + {{ 'gateway.statistics.timeout-ms' | translate }} + + + {{ 'gateway.statistics.timeout-min' | translate }} + + + + + + {{ 'gateway.statistics.command' | translate }} + + + + {{ 'widget-config.datasource-parameters' | translate }} + + edit + + + +
- - {{'gateway.rpc-command-result' | translate}} +
+ {{ 'gateway.rpc-command-result' | translate }} - - + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.scss index afdcf9b1f0..345688d451 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.scss @@ -22,24 +22,24 @@ padding: 0; .command-form { - width: 100%; flex-wrap: nowrap; - padding: 0 15px 5px; - margin-bottom: 5px; - + padding: 0 5px 5px; & > button { margin-top: 10px; } } .result-block { - padding: 0 15px; + padding: 0 5px; display: flex; flex-direction: column; - + flex: 1; & > span { font-weight: 600; } + tb-json-content { + flex: 1; + } } } @@ -47,9 +47,5 @@ .tb-json-content { height: 100%; } - - .mat-mdc-form-field-icon-suffix { - z-index: 100; - } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts index dbda5f4db2..0c2e8f8c55 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts @@ -14,17 +14,9 @@ /// limitations under the License. /// -import { AfterViewInit, Component, Input } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { Router } from '@angular/router'; +import { AfterViewInit, Component, Input } from '@angular/core'; import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { AttributeService } from '@core/http/attribute.service'; -import { DeviceService } from '@core/http/device.service'; -import { TranslateService } from '@ngx-translate/core'; -import { PageComponent } from "@shared/components/page.component"; -import { DialogService } from '@core/services/dialog.service'; import { WidgetContext } from '@home/models/widget-component.models'; import { ContentType } from '@shared/models/constants'; import { @@ -32,13 +24,12 @@ import { JsonObjectEditDialogData } from '@shared/components/dialog/json-object-edit-dialog.component'; - @Component({ selector: 'tb-gateway-service-rpc', templateUrl: './gateway-service-rpc.component.html', styleUrls: ['./gateway-service-rpc.component.scss'] }) -export class GatewayServiceRPCComponent extends PageComponent implements AfterViewInit { +export class GatewayServiceRPCComponent implements AfterViewInit { @Input() ctx: WidgetContext; @@ -52,39 +43,28 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi isConnector: boolean; - connectorType: string; - RPCCommands: Array = [ - "Ping", - "Stats", - "Devices", - "Update", - "Version", - "Restart", - "Reboot" - ] - - - constructor(protected router: Router, - protected store: Store, - protected fb: FormBuilder, - protected translate: TranslateService, - protected attributeService: AttributeService, - protected deviceService: DeviceService, - protected dialogService: DialogService, - public dialog: MatDialog) { - super(store); + 'Ping', + 'Stats', + 'Devices', + 'Update', + 'Version', + 'Restart', + 'Reboot' + ]; + + private connectorType: string; + + constructor(private fb: FormBuilder, + private dialog: MatDialog) { this.commandForm = this.fb.group({ command: [null,[Validators.required]], time: [60, [Validators.required, Validators.min(1)]], - params: ["{}", [Validators.required]], + params: ['{}', [Validators.required]], result: [null] - }) - - + }); } - ngAfterViewInit() { this.isConnector = this.ctx.settings.isConnector; if (!this.isConnector) { @@ -94,16 +74,16 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi } } - sendCommand() { const formValues = this.commandForm.value; const commandPrefix = this.isConnector ? `${this.connectorType}_` : 'gateway_'; - this.ctx.controlApi.sendTwoWayCommand(commandPrefix+formValues.command.toLowerCase(), {},formValues.time).subscribe(resp=>{ - this.commandForm.get('result').setValue(JSON.stringify(resp)); - },error => { - console.log(error); - this.commandForm.get('result').setValue(JSON.stringify(error.error)); - }) + this.ctx.controlApi.sendTwoWayCommand(commandPrefix+formValues.command.toLowerCase(), {},formValues.time).subscribe({ + next: resp => this.commandForm.get('result').setValue(JSON.stringify(resp)), + error: error => { + console.log(error); + this.commandForm.get('result').setValue(JSON.stringify(error.error)); + } + }); } openEditJSONDialog($event: Event) { @@ -124,5 +104,4 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi } ); } - } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.html index 8da9b2bce8..8671b58f46 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.html @@ -19,13 +19,13 @@
- {{'gateway.statistics.statistic' | translate}} + {{ 'gateway.statistics.statistic' | translate }} - {{key}} + {{ key }} - {{command.attributeOnGateway}} + {{ command.attributeOnGateway }} @@ -34,44 +34,42 @@ {{'gateway.statistics.statistic-commands-empty' | translate }} - {{'gateway.statistics.command' | translate}} + {{ 'gateway.statistics.command' | translate }}
-
- -
+
- {{'audit-log.timestamp' | translate}} + {{ 'widgets.gateway.created-time' | translate }} {{row[0]| date:'yyyy-MM-dd HH:mm:ss' }} - {{"event.message" | translate}} + {{ 'widgets.gateway.message' | translate }} {{ row[1] }} - -
{{'attribute.no-telemetry-text' | translate}} + class="no-data-found">{{ 'attribute.no-telemetry-text' | translate }}
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts index 90e5541217..2e1deb900a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts @@ -14,18 +14,10 @@ /// limitations under the License. /// -import { AfterViewInit, ChangeDetectorRef, Component, ElementRef, Input, ViewChild } from '@angular/core'; -import { Store } from '@ngrx/store'; -import { AppState } from '@core/core.state'; -import { Router } from '@angular/router'; +import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; -import { MatDialog } from '@angular/material/dialog'; import { AttributeService } from '@core/http/attribute.service'; -import { DeviceService } from '@core/http/device.service'; -import { TranslateService } from '@ngx-translate/core'; import { AttributeData, AttributeScope } from '@shared/models/telemetry/telemetry.models'; -import { PageComponent } from '@shared/components/page.component'; -import { DialogService } from '@core/services/dialog.service'; import { WidgetContext } from '@home/models/widget-component.models'; import { TbFlot } from '@home/components/widget/lib/flot-widget'; import { ResizeObserver } from '@juggle/resize-observer'; @@ -41,13 +33,12 @@ import { MatTableDataSource } from '@angular/material/table'; import { MatSort } from '@angular/material/sort'; import { NULL_UUID } from '@shared/models/id/has-uuid'; - @Component({ selector: 'tb-gateway-statistics', templateUrl: './gateway-statistics.component.html', styleUrls: ['./gateway-statistics.component.scss'] }) -export class GatewayStatisticsComponent extends PageComponent implements AfterViewInit { +export class GatewayStatisticsComponent implements AfterViewInit { @ViewChild(MatSort) sort: MatSort; @ViewChild('statisticChart') statisticChart: ElementRef; @@ -58,10 +49,10 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi @Input() public general: boolean; - public isNumericData: boolean = false; + public isNumericData = false; public chartInited: boolean; private flot: TbFlot; - private flotCtx; + private flotCtx: WidgetContext; public statisticForm: FormGroup; public statisticsKeys = []; public commands = []; @@ -89,70 +80,61 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi }; - constructor(protected router: Router, - protected store: Store, - protected fb: FormBuilder, - protected translate: TranslateService, - protected attributeService: AttributeService, - protected deviceService: DeviceService, - protected dialogService: DialogService, - private cd: ChangeDetectorRef, - private utils: UtilsService, - public dialog: MatDialog) { - super(store); + constructor(private fb: FormBuilder, + private attributeService: AttributeService, + private utils: UtilsService) { const sortOrder: SortOrder = {property: '0', direction: Direction.DESC}; this.pageLink = new PageLink(Number.POSITIVE_INFINITY, 0, null, sortOrder); this.displayedColumns = ['0', '1']; this.dataSource = new MatTableDataSource([]); this.statisticForm = this.fb.group({ statisticKey: [null, []] - }) + }); this.statisticForm.get('statisticKey').valueChanges.subscribe(value => { this.commandObj = null; if (this.commands.length) { this.commandObj = this.commands.find(command => command.attributeOnGateway === value); } - if (this.subscriptionInfo) this.createChartsSubscription(this.ctx.defaultSubscription.datasources[0].entity, value); - }) + if (this.subscriptionInfo) { + this.createChartsSubscription(this.ctx.defaultSubscription.datasources[0].entity, value); + } + }); } ngAfterViewInit() { this.dataSource.sort = this.sort; - this.sort.sortChange.subscribe(_=>{ - this.sortData(); - }) + this.sort.sortChange.subscribe(() => this.sortData()); this.init(); if (this.ctx.defaultSubscription.datasources.length) { const gateway = this.ctx.defaultSubscription.datasources[0].entity; - if (gateway.id.id === NULL_UUID) return; + if (gateway.id.id === NULL_UUID) { + return; + } if (!this.general) { - this.attributeService.getEntityAttributes(gateway.id, AttributeScope.SHARED_SCOPE, ["general_configuration"]).subscribe((resp: AttributeData[]) => { - if (resp && resp.length) { - this.commands = resp[0].value.statistics.commands; - if (!this.statisticForm.get('statisticKey').value && this.commands && this.commands.length) { - this.statisticForm.get('statisticKey').setValue(this.commands[0].attributeOnGateway); - this.createChartsSubscription(gateway, this.commands[0].attributeOnGateway); + this.attributeService.getEntityAttributes(gateway.id, AttributeScope.SHARED_SCOPE, ['general_configuration']) + .subscribe((resp: AttributeData[]) => { + if (resp && resp.length) { + this.commands = resp[0].value.statistics.commands; + if (!this.statisticForm.get('statisticKey').value && this.commands && this.commands.length) { + this.statisticForm.get('statisticKey').setValue(this.commands[0].attributeOnGateway); + this.createChartsSubscription(gateway, this.commands[0].attributeOnGateway); + } } - } - }) + }); } else { - let connectorsTs; this.attributeService.getEntityTimeseriesLatest(gateway.id).subscribe( data => { - connectorsTs = Object.keys(data) - .filter(el => el.includes( - 'ConnectorEventsProduced' - ) || el.includes( - 'ConnectorEventsSent')) + const connectorsTs = Object.keys(data) + .filter(el => el.includes('ConnectorEventsProduced') || el.includes('ConnectorEventsSent')); this.createGeneralChartsSubscription(gateway, connectorsTs); - }) + }); } } } - public sortData () { + public sortData() { this.dataSource.sortData(this.dataSource.data, this.sort); } @@ -162,7 +144,7 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi } private createChartsSubscription(gateway: BaseData, attr: string) { - let subscriptionInfo = [{ + const subscriptionInfo = [{ type: DatasourceType.entity, entityType: EntityType.DEVICE, entityId: gateway.id.id, @@ -175,8 +157,8 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi this.changeSubscription(subscriptionInfo); } - private createGeneralChartsSubscription(gateway: BaseData, attrData: [string]) { - let subscriptionInfo = [{ + private createGeneralChartsSubscription(gateway: BaseData, attrData: string[]) { + const subscriptionInfo = [{ type: DatasourceType.entity, entityType: EntityType.DEVICE, entityId: gateway.id.id, @@ -184,20 +166,20 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi timeseries: [] }]; subscriptionInfo[0].timeseries = []; - if (attrData && attrData.length) { + if (attrData?.length) { attrData.forEach(attr => { - subscriptionInfo[0].timeseries.push({name: attr, label: attr}) - }) + subscriptionInfo[0].timeseries.push({name: attr, label: attr}); + }); } this.ctx.defaultSubscription.datasources[0].dataKeys.forEach(dataKey => { - subscriptionInfo[0].timeseries.push({name: dataKey.name, label: dataKey.label}) - }) + subscriptionInfo[0].timeseries.push({name: dataKey.name, label: dataKey.label}); + }); this.subscriptionInfo = subscriptionInfo; this.changeSubscription(subscriptionInfo); } - init = () => { + private init = () => { this.flotCtx = { $scope: this.ctx.$scope, $injector: this.ctx.$injector, @@ -207,20 +189,20 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi subscriptionApi: this.ctx.subscriptionApi, detectChanges: this.ctx.detectChanges, settings: this.ctx.settings - }; - } + } as WidgetContext; + }; - updateChart = () => { + private updateChart = () => { if (this.flot && this.ctx.defaultSubscription.data.length) { this.flot.update(); } - } + }; - resize = () => { + private resize = () => { if (this.flot) { this.flot.resize(); } - } + }; private reset() { if (this.resize$) { @@ -260,7 +242,7 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi this.chartInited = true; this.flotCtx.$container = $(this.statisticChart.nativeElement); this.resize$.observe(this.statisticChart.nativeElement); - this.flot = new TbFlot(this.flotCtx as WidgetContext, "line"); + this.flot = new TbFlot(this.flotCtx as WidgetContext, 'line'); this.flot.update(); } @@ -270,16 +252,17 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi return; } this.dataSource.data = this.subscription.data.length ? this.subscription.data[0].data : []; - this.isNumericData = this.dataSource.data.every(data => !isNaN(+data[1]) ); + this.isNumericData = this.dataSource.data.every(data => !isNaN(+data[1])); } - changeSubscription(subscriptionInfo: SubscriptionInfo[]) { + private changeSubscription(subscriptionInfo: SubscriptionInfo[]) { if (this.subscription) { this.reset(); } if (this.ctx.datasources[0].entity) { - this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.timeseries, subscriptionInfo, this.subscriptionOptions, false, true).subscribe(subscription => { + this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.timeseries, subscriptionInfo, this.subscriptionOptions, + false, true).subscribe(subscription => { this.subscription = subscription; this.isDataOnlyNumbers(); this.legendData = this.subscription.legendData; @@ -291,9 +274,7 @@ export class GatewayStatisticsComponent extends PageComponent implements AfterVi if (this.isNumericData) { this.initChart(); } - }) - + }); } } - } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts new file mode 100644 index 0000000000..c08ee7dc89 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-widget.models.ts @@ -0,0 +1,142 @@ +/// +/// Copyright © 2016-2023 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 enum StorageTypes { + MEMORY = 'memory', + FILE = 'file', + SQLITE = 'sqlite' +} + +export enum DeviceGatewayStatus { + EXCEPTION = 'EXCEPTION' +} + +export enum GatewayLogLevel { + NONE = 'NONE', + CRITICAL = 'CRITICAL', + ERROR = 'ERROR', + WARNING = 'WARNING', + INFO = 'INFO', + DEBUG = 'DEBUG' +} + +export const GatewayStatus = { + ...GatewayLogLevel, + ...DeviceGatewayStatus +}; + +export type GatewayStatus = DeviceGatewayStatus | GatewayLogLevel; + +export enum LogSavingPeriod { + days = 'D', + hours = 'H', + minutes = 'M', + seconds = 'S' +} + +export enum LocalLogsConfigs { + service = 'service', + connector = 'connector', + converter = 'converter', + tb_connection = 'tb_connection', + storage = 'storage', + extension = 'extension' +} + +export const LocalLogsConfigTranslateMap = new Map([ + [LocalLogsConfigs.service, 'Service'], + [LocalLogsConfigs.connector, 'Connector'], + [LocalLogsConfigs.converter, 'Converter'], + [LocalLogsConfigs.tb_connection, 'TB Connection'], + [LocalLogsConfigs.storage, 'Storage'], + [LocalLogsConfigs.extension, 'Extension'] +]); + +export const LogSavingPeriodTranslations = new Map( + [ + [LogSavingPeriod.days, 'gateway.logs.days'], + [LogSavingPeriod.hours, 'gateway.logs.hours'], + [LogSavingPeriod.minutes, 'gateway.logs.minutes'], + [LogSavingPeriod.seconds, 'gateway.logs.seconds'] + ] +); + +export const StorageTypesTranslationMap = new Map( + [ + [StorageTypes.MEMORY, 'gateway.storage-types.memory-storage'], + [StorageTypes.FILE, 'gateway.storage-types.file-storage'], + [StorageTypes.SQLITE, 'gateway.storage-types.sqlite'] + ] +); + +export enum SecurityTypes { + ACCESS_TOKEN = 'accessToken', + USERNAME_PASSWORD = 'usernamePassword', + TLS_ACCESS_TOKEN = 'tlsAccessToken', + TLS_PRIVATE_KEY = 'tlsPrivateKey' +} + +export const GecurityTypesTranslationsMap = new Map( + [ + [SecurityTypes.ACCESS_TOKEN, 'gateway.security-types.access-token'], + [SecurityTypes.USERNAME_PASSWORD, 'gateway.security-types.username-password'], + [SecurityTypes.TLS_ACCESS_TOKEN, 'gateway.security-types.tls-access-token'], + // [SecurityTypes.TLS_PRIVATE_KEY, 'gateway.security-types.tls-private-key'], + ] +); + +export interface GatewayConnector { + name: string; + type: string; + configuration?: string; + configurationJson: string; + logLevel: string; + key?: string; +} + + +export const GatewayConnectorDefaultTypesTranslates = new Map([ + ['mqtt', 'MQTT'], + ['modbus', 'MODBUS'], + ['grpc', 'GRPC'], + ['opcua', 'OPCUA'], + ['opcua_asyncio', 'OPCUA ASYNCIO'], + ['ble', 'BLE'], + ['request', 'REQUEST'], + ['can', 'CAN'], + ['bacnet', 'BACNET'], + ['odbc', 'ODBC'], + ['rest', 'REST'], + ['snmp', 'SNMP'], + ['ftp', 'FTP'], + ['socket', 'SOCKET'], + ['xmpp', 'XMPP'], + ['ocpp', 'OCCP'], + ['custom', 'CUSTOM'] +]); + +export interface LogLink { + name: string; + key: string; + filterFn?: (arg: any) => boolean; +} + +export interface GatewayLogData { + ts: number; + key: string; + message: string; + status: GatewayStatus; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.html index 25d77badc7..a9e350eb95 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.html @@ -15,12 +15,13 @@ limitations under the License. --> -
- - {{"widgets.gateway.is-connector" | translate}} - - - {{"widgets.gateway.state-param-name" | translate}} - - -
+
+
+ + {{"widgets.gateway.is-connector" | translate}} + + + + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts index 74e214a3d9..5d3ea09447 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts @@ -16,7 +16,7 @@ import { Component } from '@angular/core'; import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -27,15 +27,15 @@ import { AppState } from '@core/core.state'; }) export class GatewayLogsSettingsComponent extends WidgetSettingsComponent { - GatewayLogSettingForm: UntypedFormGroup; + gatewayLogSettingForm: FormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { super(store); } - protected settingsForm(): UntypedFormGroup { - return this.GatewayLogSettingForm; + protected settingsForm(): FormGroup { + return this.gatewayLogSettingForm; } protected defaultSettings(): WidgetSettings { @@ -46,9 +46,22 @@ export class GatewayLogsSettingsComponent extends WidgetSettingsComponent { } protected onSettingsSet(settings: WidgetSettings) { - this.GatewayLogSettingForm = this.fb.group({ + this.gatewayLogSettingForm = this.fb.group({ isConnectorLog: [false, []], - connectorLogState: ['default', []] + connectorLogState: ['default', Validators.required] }); } + + protected validatorTriggers(): string[] { + return ['isConnectorLog']; + } + + protected updateValidators(emitEvent: boolean) { + const isConnectorLog: boolean = this.gatewayLogSettingForm.get('isConnectorLog').value; + if (isConnectorLog) { + this.gatewayLogSettingForm.get('connectorLogState').enable({emitEvent}); + } else { + this.gatewayLogSettingForm.get('connectorLogState').disable({emitEvent}); + } + } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.html index beeba7c2a7..391d7a9bc2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.html @@ -15,8 +15,10 @@ limitations under the License. --> -
- - {{"widgets.gateway.is-connector" | translate}} - -
+
+
+ + {{"widgets.gateway.is-connector" | translate}} + +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.ts index edafed90b8..5b0402236b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-service-rpc-settings.component.ts @@ -16,7 +16,7 @@ import { Component } from '@angular/core'; import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { FormBuilder, FormGroup } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -27,15 +27,15 @@ import { AppState } from '@core/core.state'; }) export class GatewayServiceRPCSettingsComponent extends WidgetSettingsComponent { - GatewayLogSettingForm: UntypedFormGroup; + gatewayServiceRPCSettingForm: FormGroup; constructor(protected store: Store, - private fb: UntypedFormBuilder) { + private fb: FormBuilder) { super(store); } - protected settingsForm(): UntypedFormGroup { - return this.GatewayLogSettingForm; + protected settingsForm(): FormGroup { + return this.gatewayServiceRPCSettingForm; } protected defaultSettings(): WidgetSettings { @@ -45,7 +45,7 @@ export class GatewayServiceRPCSettingsComponent extends WidgetSettingsComponent } protected onSettingsSet(settings: WidgetSettings) { - this.GatewayLogSettingForm = this.fb.group({ + this.gatewayServiceRPCSettingForm = this.fb.group({ isConnector: [false, []] }); } diff --git a/ui-ngx/src/app/shared/components/file-input.component.html b/ui-ngx/src/app/shared/components/file-input.component.html index 308e9e59f7..c0c004d02c 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.html +++ b/ui-ngx/src/app/shared/components/file-input.component.html @@ -16,12 +16,14 @@ -->
- + + + + + +
diff --git a/ui-ngx/src/app/shared/components/file-input.component.scss b/ui-ngx/src/app/shared/components/file-input.component.scss index a229a01bfb..45ed704336 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.scss +++ b/ui-ngx/src/app/shared/components/file-input.component.scss @@ -22,8 +22,10 @@ $previewSize: 100px !default; .tb-container { margin-top: 0; label.tb-title { - display: block; padding-bottom: 8px; + &:not(.pointer-event) { + display: block; + } } } 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 560402c622..7397f82993 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2635,7 +2635,7 @@ "gateway": { "add-entry": "Add configuration", "advanced": "Advanced", - "checking-device-activity": "Checking Device Activity:", + "checking-device-activity": "Checking device activity", "command": "Docker commands", "command-copied-message": "Docker command has been copied to clipboard", "configuration": "Configuration", @@ -2888,7 +2888,7 @@ "log-format": "Log message format", "remote-log": "Enables remote logging and logs reading from the gateway", "backup-count": "If backup count is > 0, when a rollover is done, no more than backup count files are kept - the oldest ones are deleted", - "storage": "Provides configuration for saving incoming data before it is sent to the ThingsBoard platform", + "storage": "Provides configuration for saving incoming data before it is sent to the platform", "file": "Received data saving to the hard drive", "memory": "Received data saving to the RAM memory", "sqlite": "Received data saving to the .db file", @@ -5330,7 +5330,10 @@ "events-filter": "Events filter", "event-key-contains": "Event key contains...", "is-connector": "Is Connector", - "state-param-name": "State parameter connector name" + "state-param-name": "State parameter connector name", + "status": "Status", + "message": "Message", + "created-time": "Created time" }, "gauge": { "default-color": "Default color", diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 141a8db6ea..63f126f405 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -65,6 +65,9 @@ box-shadow: none; border-radius: 0; } + &.no-gap { + gap: 0; + } &.tb-slide-toggle { padding: 0; gap: 0; @@ -218,7 +221,7 @@ } } - .tb-form-row .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { + .tb-form-row:not(.tb-not-inline-field) .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { &.mat-form-field-appearance-fill { .mdc-text-field--filled:not(.mdc-text-field--disabled) { &:before { From 66f598b4d84b7f0322666ddd1bbde9021857bde9 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Tue, 12 Sep 2023 11:13:57 +0300 Subject: [PATCH 019/267] refactored KvUtils.validate method --- dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java b/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java index f94d76ba89..31bb00ebd9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/KvUtils.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.util; import com.fasterxml.jackson.databind.JsonNode; import com.github.benmanes.caffeine.cache.Cache; import com.github.benmanes.caffeine.cache.Caffeine; +import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.dao.exception.DataValidationException; import org.thingsboard.server.dao.exception.IncorrectParameterException; @@ -48,7 +49,7 @@ public class KvUtils { String key = tsKvEntry.getKey(); - if (key == null || key.isBlank()) { + if (StringUtils.isBlank(key)) { throw new DataValidationException("Key can't be null or empty"); } From 3f10ba464e96106f77688c641829e7874c146a29 Mon Sep 17 00:00:00 2001 From: Shvaika Dmytro Date: Tue, 12 Sep 2023 12:16:31 +0300 Subject: [PATCH 020/267] added executor to speed up rule nodes upgrade & added SQL upgrade for TbMsgAttributesNode & updated logback.xml with new debug entry to view the rule node upgrade logs (#9224) * added executor to speed up rule nodes upgrade & added SQL upgrade for TbMsgAttributesNode & updated logback.xml with new debug entry to view the rule node upgrade logs * refactoring after review * create index before upsert * added missing logic to await futures to be completed with max pending futures size set to 100 * added better logging * refacotring after review --- .../install/SqlDatabaseUpgradeService.java | 7 +++ .../update/DefaultDataUpdateService.java | 44 ++++++++++++++----- application/src/main/resources/logback.xml | 2 + 3 files changed, 43 insertions(+), 10 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 4bb29426c9..9e942b481e 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 @@ -756,6 +756,13 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_rule_node_type_configuration_version ON rule_node(type, configuration_version);"); } catch (Exception e) { } + try { + conn.createStatement().execute("UPDATE rule_node SET " + + "configuration = (configuration::jsonb || '{\"updateAttributesOnlyOnValueChange\": \"false\"}'::jsonb)::varchar, " + + "configuration_version = 1 " + + "WHERE type = 'org.thingsboard.rule.engine.telemetry.TbMsgAttributesNode' AND configuration_version < 1;"); + } catch (Exception e) { + } try { conn.createStatement().execute("CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_unread ON notification(recipient_id) WHERE status <> 'READ';"); } catch (Exception e) { 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 a1048d6a37..8c3b78040b 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 @@ -78,6 +78,7 @@ import org.thingsboard.server.dao.model.sql.DeviceProfileEntity; import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.relation.RelationService; import org.thingsboard.server.dao.rule.RuleChainService; +import org.thingsboard.server.dao.sql.JpaExecutorService; import org.thingsboard.server.dao.sql.device.DeviceProfileRepository; import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.tenant.TenantService; @@ -101,6 +102,8 @@ import static org.thingsboard.server.common.data.StringUtils.isBlank; @Slf4j public class DefaultDataUpdateService implements DataUpdateService { + private static final int MAX_PENDING_SAVE_RULE_NODE_FUTURES = 100; + @Autowired private TenantService tenantService; @@ -153,6 +156,9 @@ public class DefaultDataUpdateService implements DataUpdateService { @Autowired private EdgeEventDao edgeEventDao; + @Autowired + JpaExecutorService jpaExecutorService; + @Override public void updateData(String fromVersion) throws Exception { switch (fromVersion) { @@ -225,13 +231,15 @@ public class DefaultDataUpdateService implements DataUpdateService { @Override public void upgradeRuleNodes() { try { + var futures = new ArrayList>(100); + int totalRuleNodesUpgraded = 0; log.info("Starting rule nodes upgrade ..."); var nodeClassToVersionMap = componentDiscoveryService.getVersionedNodes(); log.debug("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size()); - nodeClassToVersionMap.forEach(clazz -> { - var ruleNodeType = clazz.getClassName(); - var ruleNodeTypeForLogs = clazz.getSimpleName(); - var toVersion = clazz.getCurrentVersion(); + for (var ruleNodeClassInfo : nodeClassToVersionMap) { + var ruleNodeType = ruleNodeClassInfo.getClassName(); + var ruleNodeTypeForLogs = ruleNodeClassInfo.getSimpleName(); + var toVersion = ruleNodeClassInfo.getCurrentVersion(); log.debug("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion); var ruleNodesToUpdate = new PageDataIterable<>( pageLink -> ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeType, toVersion, pageLink), 1024 @@ -246,28 +254,44 @@ public class DefaultDataUpdateService implements DataUpdateService { log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); try { - var tbVersionedNode = (TbNode) clazz.getClazz().getDeclaredConstructor().newInstance(); + var tbVersionedNode = (TbNode) ruleNodeClassInfo.getClazz().getDeclaredConstructor().newInstance(); TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration); if (upgradeRuleNodeConfigurationResult.getFirst()) { ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond()); } ruleNode.setConfigurationVersion(toVersion); - ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode); - log.debug("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); + futures.add(jpaExecutorService.submit(() -> { + ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode); + log.debug("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", + ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); + })); + if (futures.size() >= MAX_PENDING_SAVE_RULE_NODE_FUTURES) { + log.info("{} upgraded rule nodes so far ...", + totalRuleNodesUpgraded += awaitFuturesToCompleteAndGetCount(futures)); + futures.clear(); + } } catch (Exception e) { log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ", ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion, e); } } } - }); - log.info("Finished rule nodes upgrade!"); + } + log.info("Finished rule nodes upgrade. Upgraded rule nodes count: {}", + totalRuleNodesUpgraded + awaitFuturesToCompleteAndGetCount(futures)); } catch (Exception e) { log.error("Unexpected error during rule nodes upgrade: ", e); } } + private int awaitFuturesToCompleteAndGetCount(List> futures) { + try { + return Futures.allAsList(futures).get().size(); + } catch (ExecutionException | InterruptedException e) { + throw new RuntimeException("Failed to process save rule nodes requests due to: ", e); + } + } + private final PaginatedUpdater deviceProfileEntityDynamicConditionsUpdater = new PaginatedUpdater<>() { diff --git a/application/src/main/resources/logback.xml b/application/src/main/resources/logback.xml index eaf6ace29e..b0a4174012 100644 --- a/application/src/main/resources/logback.xml +++ b/application/src/main/resources/logback.xml @@ -30,6 +30,8 @@ + + From e369218a1fe386b153530bf9af4744d88c58c0bc Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 12 Sep 2023 12:17:54 +0300 Subject: [PATCH 021/267] Fix rule node query performance --- .../server/dao/rule/RuleNodeDao.java | 2 +- .../server/dao/sql/rule/JpaRuleNodeDao.java | 4 +- .../dao/sql/rule/RuleNodeRepository.java | 13 +- .../dao/sql/rule/JpaRuleNodeDaoTest.java | 158 ++++++++++++++++++ 4 files changed, 169 insertions(+), 8 deletions(-) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java 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 7df394ddd4..cd8fbb0a3c 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 @@ -30,7 +30,7 @@ import java.util.List; */ public interface RuleNodeDao extends Dao { - List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search); + List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String configurationSearch); PageData findAllRuleNodesByType(String type, PageLink pageLink); 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 7adf8aa0c8..827b73a0c1 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 @@ -56,8 +56,8 @@ public class JpaRuleNodeDao extends JpaAbstractDao imp } @Override - public List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String search) { - return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByTenantIdAndType(tenantId.getId(), type, search)); + public List findRuleNodesByTenantIdAndType(TenantId tenantId, String type, String configurationSearch) { + return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByTenantIdAndType(tenantId.getId(), type, configurationSearch)); } @Override 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 e016462255..c8ecb8000b 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 @@ -29,19 +29,22 @@ import java.util.UUID; public interface RuleNodeRepository extends JpaRepository { - @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, '%')) ") + @Query(nativeQuery = true, value = "SELECT * FROM rule_node r WHERE r.rule_chain_id in " + + "(select id from rule_chain rc WHERE rc.tenant_id = :tenantId) AND r.type = :ruleType " + + " AND (:searchText IS NULL OR r.configuration ILIKE CONCAT('%', :searchText, '%'))") List findRuleNodesByTenantIdAndType(@Param("tenantId") UUID tenantId, @Param("ruleType") String ruleType, @Param("searchText") String searchText); - @Query("SELECT r FROM RuleNodeEntity r WHERE r.type = :ruleType AND LOWER(r.configuration) LIKE LOWER(CONCAT('%', :searchText, '%')) ") + @Query(nativeQuery = true, value = "SELECT * FROM rule_node r WHERE r.type = :ruleType " + + " AND (:searchText IS NULL OR r.configuration ILIKE CONCAT('%', :searchText, '%'))") Page findAllRuleNodesByType(@Param("ruleType") String ruleType, @Param("searchText") String searchText, Pageable pageable); - @Query("SELECT r FROM RuleNodeEntity r WHERE r.type = :ruleType AND r.configurationVersion < :version AND LOWER(r.configuration) LIKE LOWER(CONCAT('%', :searchText, '%')) ") + @Query(nativeQuery = true, value = "SELECT * FROM rule_node r WHERE r.type = :ruleType " + + " AND configuration_version < :version " + + " AND (:searchText IS NULL OR r.configuration ILIKE CONCAT('%', :searchText, '%'))") Page findAllRuleNodesByTypeAndVersionLessThan(@Param("ruleType") String ruleType, @Param("version") int version, @Param("searchText") String searchText, diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java new file mode 100644 index 0000000000..6e77927233 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java @@ -0,0 +1,158 @@ +/** + * Copyright © 2016-2023 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.rule; + +import com.datastax.oss.driver.api.core.uuid.Uuids; +import com.google.common.util.concurrent.ListeningExecutorService; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.common.util.JacksonUtil; +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; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.rule.RuleChain; +import org.thingsboard.server.common.data.rule.RuleNode; +import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.rule.RuleChainDao; +import org.thingsboard.server.dao.rule.RuleNodeDao; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class JpaRuleNodeDaoTest extends AbstractJpaDaoTest { + + public static final int COUNT = 40; + public static final String PREFIX_FOR_RULE_NODE_NAME = "SEARCH_TEXT_"; + List ruleNodeIds; + TenantId tenantId1; + TenantId tenantId2; + RuleChainId ruleChainId1; + RuleChainId ruleChainId2; + + @Autowired + private RuleChainDao ruleChainDao; + + @Autowired + private RuleNodeDao ruleNodeDao; + + ListeningExecutorService executor; + + @Before + public void setUp() { + tenantId1 = TenantId.fromUUID(Uuids.timeBased()); + ruleChainId1 = new RuleChainId(UUID.randomUUID()); + tenantId2 = TenantId.fromUUID(Uuids.timeBased()); + ruleChainId2 = new RuleChainId(UUID.randomUUID()); + + ruleNodeIds = createRuleNodes(tenantId1, tenantId2, ruleChainId1, ruleChainId2, COUNT); + } + + @After + public void tearDown() throws Exception { + ruleNodeDao.removeAllByIds(ruleNodeIds); + if (executor != null) { + executor.shutdownNow(); + } + } + + @Test + public void testSaveRuleName0x00_thenSomeDatabaseException() { + RuleNode ruleNode = getRuleNode(ruleChainId1, "T", "\u0000"); + assertThatThrownBy(() -> ruleNodeIds.add(ruleNodeDao.save(tenantId1, ruleNode).getUuidId())); + } + + @Test + public void testFindRuleNodesByTenantIdAndType() { + List ruleNodes1 = ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId1, "A", PREFIX_FOR_RULE_NODE_NAME); + assertEquals(20, ruleNodes1.size()); + + List ruleNodes2 = ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId2, "B", PREFIX_FOR_RULE_NODE_NAME); + assertEquals(20, ruleNodes2.size()); + + ruleNodes1 = ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId1, "A", null); + assertEquals(20, ruleNodes1.size()); + + ruleNodes2 = ruleNodeDao.findRuleNodesByTenantIdAndType(tenantId2, "B", null); + assertEquals(20, ruleNodes2.size()); + } + + @Test + public void testFindRuleNodesByType() { + PageData ruleNodes = ruleNodeDao.findAllRuleNodesByType( "A", new PageLink(10, 0, PREFIX_FOR_RULE_NODE_NAME)); + assertEquals(20, ruleNodes.getTotalElements()); + assertEquals(2, ruleNodes.getTotalPages()); + assertEquals(10, ruleNodes.getData().size()); + + ruleNodes = ruleNodeDao.findAllRuleNodesByType( "A", new PageLink(10, 0)); + assertEquals(20, ruleNodes.getTotalElements()); + assertEquals(2, ruleNodes.getTotalPages()); + assertEquals(10, ruleNodes.getData().size()); + } + + @Test + public void testFindRuleNodesByTypeAndVersionLessThan() { + PageData ruleNodes = ruleNodeDao.findAllRuleNodesByTypeAndVersionLessThan( "A", 1, new PageLink(10, 0, PREFIX_FOR_RULE_NODE_NAME)); + assertEquals(20, ruleNodes.getTotalElements()); + assertEquals(2, ruleNodes.getTotalPages()); + assertEquals(10, ruleNodes.getData().size()); + + ruleNodes = ruleNodeDao.findAllRuleNodesByTypeAndVersionLessThan( "A", 1, new PageLink(10, 0)); + assertEquals(20, ruleNodes.getTotalElements()); + assertEquals(2, ruleNodes.getTotalPages()); + assertEquals(10, ruleNodes.getData().size()); + } + + private List createRuleNodes(TenantId tenantId1, TenantId tenantId2, RuleChainId ruleChainId1, RuleChainId ruleChainId2, int count) { + var chain1 = new RuleChain(ruleChainId1); + chain1.setTenantId(tenantId1); + chain1.setName(ruleChainId1.toString()); + ruleChainDao.save(tenantId1, chain1); + var chain2 = new RuleChain(ruleChainId2); + chain2.setTenantId(tenantId2); + chain2.setName(ruleChainId2.toString()); + ruleChainDao.save(tenantId2, chain2); + List savedRuleNodeIds = new ArrayList<>(); + for (int i = 0; i < count / 2; i++) { + savedRuleNodeIds.add(ruleNodeDao.save(tenantId1, getRuleNode(ruleChainId1, "A", Integer.toString(i))).getUuidId()); + savedRuleNodeIds.add(ruleNodeDao.save(tenantId2, getRuleNode(ruleChainId2, "B", Integer.toString(i + count / 2))).getUuidId()); + } + return savedRuleNodeIds; + } + + private RuleNode getRuleNode(RuleChainId ruleChainId, String type, String nameSuffix) { + return getRuleNode(ruleChainId, Uuids.timeBased(), type, nameSuffix); + } + + private RuleNode getRuleNode(RuleChainId ruleChainId, UUID ruleNodeId, String type, String nameSuffix) { + RuleNode ruleNode = new RuleNode(); + ruleNode.setId(new RuleNodeId(ruleNodeId)); + ruleNode.setRuleChainId(ruleChainId); + ruleNode.setName(nameSuffix); + ruleNode.setType(type); + ruleNode.setConfiguration(JacksonUtil.newObjectNode().put("searchHint", PREFIX_FOR_RULE_NODE_NAME + nameSuffix)); + ruleNode.setConfigurationVersion(0); + return ruleNode; + } +} From 4114c96571dbb35c1655cd77faa4bb4872c237c8 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 12 Sep 2023 12:32:35 +0300 Subject: [PATCH 022/267] Version control: fix ids replacement in dashboard config --- .../impl/BaseEntityExportService.java | 4 +- .../impl/DashboardExportService.java | 5 +- .../impl/BaseEntityImportService.java | 6 +-- .../impl/DashboardImportService.java | 4 +- .../sync/ie/ExportImportServiceSqlTest.java | 53 ++++++++++++++++--- .../thingsboard/common/util/JacksonUtil.java | 21 ++++---- 6 files changed, 66 insertions(+), 27 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java index abc90221be..3cf05ac503 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/BaseEntityExportService.java @@ -48,8 +48,8 @@ public abstract class BaseEntityExportService getSupportedEntityTypes(); - protected void replaceUuidsRecursively(EntitiesExportCtx ctx, JsonNode node, Set skipFieldsSet, Pattern includedFieldsPattern) { - JacksonUtil.replaceUuidsRecursively(node, skipFieldsSet, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid)); + protected void replaceUuidsRecursively(EntitiesExportCtx ctx, JsonNode node, Set skippedRootFields, Pattern includedFieldsPattern) { + JacksonUtil.replaceUuidsRecursively(node, skippedRootFields, includedFieldsPattern, uuid -> getExternalIdOrElseInternalByUuid(ctx, uuid), true); } protected Stream toExternalIds(Collection internalIds, Function entityIdCreator, diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java index 0df1e83c7f..d1278bc585 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/exporting/impl/DashboardExportService.java @@ -26,8 +26,11 @@ import org.thingsboard.server.common.data.sync.ie.EntityExportData; import org.thingsboard.server.queue.util.TbCoreComponent; import org.thingsboard.server.service.sync.vc.data.EntitiesExportCtx; +import java.util.Collections; import java.util.Set; +import static org.thingsboard.server.service.sync.ie.importing.impl.DashboardImportService.WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN; + @Service @TbCoreComponent public class DashboardExportService extends BaseEntityExportService> { @@ -43,7 +46,7 @@ public class DashboardExportService extends BaseEntityExportService skipFieldsSet, Pattern includedFieldsPattern, + Set skippedRootFields, Pattern includedFieldsPattern, LinkedHashSet hints) { - JacksonUtil.replaceUuidsRecursively(json, skipFieldsSet, includedFieldsPattern, + JacksonUtil.replaceUuidsRecursively(json, skippedRootFields, includedFieldsPattern, uuid -> idProvider.getInternalIdByUuid(uuid, ctx.isFinalImportAttempt(), hints) - .map(EntityId::getId).orElse(uuid)); + .map(EntityId::getId).orElse(uuid), true); } } diff --git a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java index eac229f774..658ecf744a 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/ie/importing/impl/DashboardImportService.java @@ -36,6 +36,7 @@ import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Optional; import java.util.Set; +import java.util.regex.Pattern; import java.util.stream.Collectors; @Service @@ -44,6 +45,7 @@ import java.util.stream.Collectors; public class DashboardImportService extends BaseEntityImportService> { private static final LinkedHashSet HINTS = new LinkedHashSet<>(Arrays.asList(EntityType.DASHBOARD, EntityType.DEVICE, EntityType.ASSET)); + public static final Pattern WIDGET_CONFIG_PROCESSED_FIELDS_PATTERN = Pattern.compile(".*Id.*"); private final DashboardService dashboardService; @@ -68,7 +70,7 @@ public class DashboardImportService extends BaseEntityImportService asset1ExportData = exportEntity(tenantAdmin1, asset1.getId()); EntityExportData asset2ExportData = exportEntity(tenantAdmin1, asset2.getId()); EntityExportData dashboardExportData = exportEntity(tenantAdmin1, dashboard.getId()); + EntityExportData otherDashboardExportData = exportEntity(tenantAdmin1, otherDashboard.getId()); AssetProfile importedProfile = importEntity(tenantAdmin2, profileExportData).getSavedEntity(); Asset importedAsset1 = importEntity(tenantAdmin2, asset1ExportData).getSavedEntity(); Asset importedAsset2 = importEntity(tenantAdmin2, asset2ExportData).getSavedEntity(); + Dashboard importedOtherDashboard = importEntity(tenantAdmin2, otherDashboardExportData).getSavedEntity(); Dashboard importedDashboard = importEntity(tenantAdmin2, dashboardExportData).getSavedEntity(); Map.Entry entityAlias = importedDashboard.getConfiguration().get("entityAliases").fields().next(); @@ -311,6 +337,17 @@ public class ExportImportServiceSqlTest extends BaseExportImportServiceTest { .isEqualTo(existingDeviceProfile.getId().toString()); assertThat(aliasEntitiesIds).element(4).as("unresolved uuid was replaced with tenant id") .isEqualTo(tenantId2.toString()); + assertThat(entityAlias.getValue().get("filter").get("id").asText()).as("external asset 1 was replaced with imported one") + .isEqualTo(importedAsset1.getId().toString()); + + ObjectNode widgetConfig = importedDashboard.getWidgetsConfig().get(0); + assertThat(widgetConfig.get("id").asText()).as("widget id is not replaced") + .isEqualTo(widgetId); + JsonNode actionConfig = widgetConfig.get("config").get("actions").get("rowClick").get(0); + assertThat(actionConfig.get("id").asText()).as("action id is not replaced") + .isEqualTo(actionId); + assertThat(actionConfig.get("targetDashboardId").asText()).as("dashboard id is replaced with imported one") + .isEqualTo(importedOtherDashboard.getId().toString()); } 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 9f980f36c8..7c8d174af2 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 @@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; +import com.google.common.collect.Lists; import org.thingsboard.server.common.data.kv.DataType; import org.thingsboard.server.common.data.kv.KvEntry; @@ -35,7 +36,6 @@ import java.io.File; import java.io.IOException; import java.io.Reader; import java.io.Writer; -import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Iterator; @@ -228,27 +228,24 @@ public class JacksonUtil { return node; } - public static void replaceUuidsRecursively(JsonNode node, Set skipFieldsSet, Pattern includedFieldsPattern, UnaryOperator replacer) { + public static void replaceUuidsRecursively(JsonNode node, Set skippedRootFields, Pattern includedFieldsPattern, UnaryOperator replacer, boolean root) { if (node == null) { return; } if (node.isObject()) { ObjectNode objectNode = (ObjectNode) node; - List fieldNames = new ArrayList<>(objectNode.size()); - objectNode.fieldNames().forEachRemaining(fieldNames::add); + List fieldNames = Lists.newArrayList(objectNode.fieldNames()); for (String fieldName : fieldNames) { - if (skipFieldsSet.contains(fieldName)) { + if (root && skippedRootFields.contains(fieldName)) { continue; } - if (includedFieldsPattern != null) { - if (!RegexUtils.matches(fieldName, includedFieldsPattern)) { - continue; - } - } var child = objectNode.get(fieldName); if (child.isObject() || child.isArray()) { - replaceUuidsRecursively(child, skipFieldsSet, includedFieldsPattern, replacer); + replaceUuidsRecursively(child, skippedRootFields, includedFieldsPattern, replacer, false); } else if (child.isTextual()) { + if (includedFieldsPattern != null && !RegexUtils.matches(fieldName, includedFieldsPattern)) { + continue; + } String text = child.asText(); String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString()); if (!text.equals(newText)) { @@ -261,7 +258,7 @@ public class JacksonUtil { for (int i = 0; i < array.size(); i++) { JsonNode arrayElement = array.get(i); if (arrayElement.isObject() || arrayElement.isArray()) { - replaceUuidsRecursively(arrayElement, skipFieldsSet, includedFieldsPattern, replacer); + replaceUuidsRecursively(arrayElement, skippedRootFields, includedFieldsPattern, replacer, false); } else if (arrayElement.isTextual()) { String text = arrayElement.asText(); String newText = RegexUtils.replace(text, RegexUtils.UUID_PATTERN, uuid -> replacer.apply(UUID.fromString(uuid)).toString()); From ece3540f969c4e0aafc67ed461be04380c781c1f Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 12 Sep 2023 13:03:00 +0300 Subject: [PATCH 023/267] UI: Allow empty array in json object edit form. --- .../add-attribute-dialog.component.html | 2 +- .../add-attribute-dialog.component.ts | 5 +++ .../edit-attribute-value-panel.component.html | 2 +- .../edit-attribute-value-panel.component.ts | 5 +++ .../gateway/gateway-connectors.component.html | 2 +- .../lib/gateway/gateway-form.component.ts | 1 + .../gateway/gateway-service-rpc.component.ts | 6 ++- .../lib/json-input-widget.component.html | 6 +-- .../lib/json-input-widget.component.scss | 4 ++ .../widget/lib/json-input-widget.component.ts | 7 +-- .../lib/multiple-input-widget.component.html | 4 +- .../lib/multiple-input-widget.component.ts | 16 ++++++- .../widget/widget-config.component.html | 1 - .../rulechain/rule-node-config.component.html | 2 +- .../json-object-edit-dialog.component.html | 3 +- .../json-object-edit-dialog.component.ts | 3 ++ .../directives/tb-json-to-string.directive.ts | 37 ++++++++++------ .../json-object-edit.component.html | 2 +- .../components/json-object-edit.component.ts | 44 ++++++++----------- .../components/value-input.component.html | 2 +- .../components/value-input.component.ts | 9 ++-- 21 files changed, 101 insertions(+), 62 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html index 17e31854cc..56a6ca46c0 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.html @@ -55,7 +55,7 @@
diff --git a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts index aadb96c142..dc13dac0df 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/add-attribute-dialog.component.ts @@ -72,6 +72,11 @@ export class AddAttributeDialogComponent extends DialogComponent
diff --git a/ui-ngx/src/app/modules/home/components/attribute/edit-attribute-value-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/edit-attribute-value-panel.component.ts index 539c9930db..4ce038a4ed 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/edit-attribute-value-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/edit-attribute-value-panel.component.ts @@ -62,6 +62,11 @@ export class EditAttributeValuePanelComponent extends PageComponent implements O return originalErrorState || customErrorState; } + invalid(): boolean { + const value = this.attributeFormGroup.get('value').value; + return !Array.isArray(value) && this.attributeFormGroup.invalid; + } + cancel(): void { this.overlayRef.dispose(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index 6e4178fccd..f3aefedbce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -179,7 +179,7 @@ diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.ts index 9840db6efe..0314120995 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-form.component.ts @@ -286,6 +286,7 @@ export class GatewayFormComponent extends PageComponent implements OnInit, OnDes panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { jsonValue: config, + required: true, title: this.translate.instant('gateway.title-connectors-json', {typeName: type}) } }).afterClosed().subscribe( diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts index dbda5f4db2..941731f7e0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts @@ -31,6 +31,7 @@ import { JsonObjectEditDialogComponent, JsonObjectEditDialogData } from '@shared/components/dialog/json-object-edit-dialog.component'; +import { jsonRequired } from '@shared/components/json-object-edit.component'; @Component({ @@ -77,7 +78,7 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi this.commandForm = this.fb.group({ command: [null,[Validators.required]], time: [60, [Validators.required, Validators.min(1)]], - params: ["{}", [Validators.required]], + params: [{}, [jsonRequired]], result: [null] }) @@ -114,7 +115,8 @@ export class GatewayServiceRPCComponent extends PageComponent implements AfterVi disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - jsonValue: JSON.parse(this.commandForm.get('params').value) + jsonValue: JSON.parse(this.commandForm.get('params').value), + required: true } }).afterClosed().subscribe( (res) => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html index 24fe07d92b..40636a9d1b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/json-input-widget.component.html @@ -26,14 +26,14 @@ -
+
- - + {{ getErrorMessageText(key.settings,'required') }} @@ -193,7 +193,7 @@
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 d4c0ad2630..eb3b0c9abf 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 @@ -604,7 +604,8 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } public inputChanged(source: MultipleInputWidgetSource, key: MultipleInputWidgetDataKey) { - if (!this.settings.showActionButtons && !this.isSavingInProgress && this.multipleInputFormGroup.get(key.formId).valid) { + const control = this.multipleInputFormGroup.get(key.formId); + if (!this.settings.showActionButtons && !this.isSavingInProgress && (Array.isArray(control.value) || control.valid)) { this.isSavingInProgress = true; const dataToSave: MultipleInputWidgetSource = { datasource: source.datasource, @@ -775,6 +776,7 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { jsonValue: formControl.value, + required: key.settings.required, title: key.settings.dialogTitle, saveLabel: key.settings.saveButtonLabel, cancelLabel: key.settings.cancelButtonLabel @@ -791,4 +793,16 @@ export class MultipleInputWidgetComponent extends PageComponent implements OnIni } ); } + + invalid(): boolean { + for (const source of this.sources) { + for (const key of this.visibleKeys(source)) { + const control = this.multipleInputFormGroup.get(key.formId); + if (!Array.isArray(control.value) && control.invalid) { + return true; + } + } + } + return false; + } } 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 732d6e3119..cdd1d8e2da 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 @@ -89,7 +89,6 @@ diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html index 97f2214f2e..6d059fddec 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rule-node-config.component.html @@ -22,7 +22,7 @@ class="tb-rule-node-configuration-json" formControlName="configuration" [label]="'rulenode.configuration' | translate" - [required]="required" + [jsonRequired]="required" [fillHeight]="true">
diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html index 141979d8ff..3b216bda71 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.html @@ -33,8 +33,7 @@ diff --git a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts index e55431a327..4aeed2a360 100644 --- a/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts +++ b/ui-ngx/src/app/shared/components/dialog/json-object-edit-dialog.component.ts @@ -26,6 +26,7 @@ import { isNotEmptyStr } from '@core/utils'; export interface JsonObjectEditDialogData { jsonValue: object; + required?: boolean; title?: string; saveLabel?: string; cancelLabel?: string; @@ -43,6 +44,8 @@ export class JsonObjectEditDialogComponent extends DialogComponent, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: JsonObjectEditDialogData, diff --git a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts index 8da5fb1396..c70de1ab48 100644 --- a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts +++ b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts @@ -17,19 +17,23 @@ import { Directive, ElementRef, forwardRef, HostListener, Renderer2, SkipSelf } from '@angular/core'; import { ControlValueAccessor, - UntypedFormControl, FormGroupDirective, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgForm, + UntypedFormControl, ValidationErrors, Validator } from '@angular/forms'; import { ErrorStateMatcher } from '@angular/material/core'; -import { isObject } from "@core/utils"; +import { isObject } from '@core/utils'; @Directive({ selector: '[tb-json-to-string]', + // eslint-disable-next-line @angular-eslint/no-host-metadata-property + host: { + '(blur)': 'onTouched()' + }, providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => TbJsonToStringDirective), @@ -48,18 +52,26 @@ import { isObject } from "@core/utils"; export class TbJsonToStringDirective implements ControlValueAccessor, Validator, ErrorStateMatcher { private propagateChange = null; + public onTouched = () => {}; private parseError: boolean; private data: any; @HostListener('input', ['$event.target.value']) input(newValue: any): void { try { - this.data = JSON.parse(newValue); - if (isObject(this.data)) { - this.parseError = false; + if (newValue) { + this.data = JSON.parse(newValue); + if (isObject(this.data)) { + this.parseError = false; + } else { + this.data = null; + this.parseError = true; + } } else { - this.parseError = true; + this.data = null; + this.parseError = false; } } catch (e) { + this.data = null; this.parseError = true; } @@ -73,9 +85,7 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator, } isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { - const originalErrorState = this.errorStateMatcher.isErrorState(control, form); - const customErrorState = !!(control && control.invalid && this.parseError); - return originalErrorState || customErrorState; + return !!(control && control.invalid && !Array.isArray(control.value) && control.touched); } validate(c: UntypedFormControl): ValidationErrors { @@ -87,11 +97,9 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator, } writeValue(obj: any): void { - if (obj) { - this.data = obj; - this.parseError = false; - this.render.setProperty(this.element.nativeElement, 'value', JSON.stringify(obj)); - } + this.data = obj; + this.parseError = false; + this.render.setProperty(this.element.nativeElement, 'value', obj ? JSON.stringify(obj) : ''); } registerOnChange(fn: any): void { @@ -99,5 +107,6 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator, } registerOnTouched(fn: any): void { + this.onTouched = fn; } } diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.html b/ui-ngx/src/app/shared/components/json-object-edit.component.html index c0024da9dd..3ed828e6cf 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.html +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.html @@ -20,7 +20,7 @@ [fullscreen]="fullscreen" (fullscreenChanged)="onFullscreen()" fxLayout="column">
diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts index f7e3116b0f..f89430f98b 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.ts @@ -24,7 +24,14 @@ import { OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms'; +import { + ControlValueAccessor, + UntypedFormControl, + NG_VALIDATORS, + NG_VALUE_ACCESSOR, + Validator, + AbstractControl, ValidationErrors +} from '@angular/forms'; import { Ace } from 'ace-builds'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions'; @@ -34,6 +41,9 @@ import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; import { guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { getAce } from '@shared/models/ace/ace.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; + +export const jsonRequired = (control: AbstractControl): ValidationErrors | null => !control.value ? {required: true} : null; @Component({ selector: 'tb-json-object-edit', @@ -73,27 +83,13 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va @Input() sort: (key: string, value: any) => any; - private requiredValue: boolean; - - get required(): boolean { - return this.requiredValue; - } - + @coerceBoolean() @Input() - set required(value: boolean) { - this.requiredValue = coerceBooleanProperty(value); - } - - private readonlyValue: boolean; - - get readonly(): boolean { - return this.readonlyValue; - } + jsonRequired: boolean; + @coerceBoolean() @Input() - set readonly(value: boolean) { - this.readonlyValue = coerceBooleanProperty(value); - } + readonly: boolean; fullscreen = false; @@ -245,12 +241,10 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va try { if (isDefinedAndNotNull(this.modelValue)) { this.contentValue = JSON.stringify(this.modelValue, isUndefined(this.sort) ? undefined : - (key, objectValue) => { - return this.sort(key, objectValue); - }, 2); + (key, objectValue) => this.sort(key, objectValue), 2); this.objectValid = true; } else { - this.objectValid = !this.required; + this.objectValid = !this.jsonRequired; this.validationError = 'Json object is required.'; } } catch (e) { @@ -288,8 +282,8 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va this.validationError = errorInfo; } } else { - this.objectValid = !this.required; - this.validationError = this.required ? 'Json object is required.' : ''; + this.objectValid = !this.jsonRequired; + this.validationError = this.jsonRequired ? 'Json object is required.' : ''; } this.modelValue = data; this.propagateChange(data); diff --git a/ui-ngx/src/app/shared/components/value-input.component.html b/ui-ngx/src/app/shared/components/value-input.component.html index 57d6954699..9f7f9d0ffc 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.html +++ b/ui-ngx/src/app/shared/components/value-input.component.html @@ -67,7 +67,7 @@ - + {{ (requiredText ? requiredText : 'value.json-value-required') | translate }} diff --git a/ui-ngx/src/app/shared/components/value-input.component.ts b/ui-ngx/src/app/shared/components/value-input.component.ts index 4ba7abf157..52828cec35 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.ts +++ b/ui-ngx/src/app/shared/components/value-input.component.ts @@ -15,7 +15,7 @@ /// import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm, NgModel } from '@angular/forms'; import { ValueType, valueTypesMap } from '@shared/models/constants'; import { isObject } from '@core/utils'; import { MatDialog } from '@angular/material/dialog'; @@ -23,6 +23,7 @@ import { JsonObjectEditDialogComponent, JsonObjectEditDialogData } from '@shared/components/dialog/json-object-edit-dialog.component'; +import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-value-input', @@ -73,7 +74,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor { disableClose: true, panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], data: { - jsonValue: this.modelValue + jsonValue: this.modelValue, + required: true } }).afterClosed().subscribe( (res) => { @@ -115,7 +117,8 @@ export class ValueInputComponent implements OnInit, ControlValueAccessor { } updateView() { - if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN) { + if (this.inputForm.valid || this.valueType === ValueType.BOOLEAN || + (this.valueType === ValueType.JSON && Array.isArray(this.modelValue))) { this.propagateChange(this.modelValue); } else { this.propagateChange(null); From b3a8ce17be81fd97608eb993e413c680e1806603 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 12 Sep 2023 13:08:59 +0300 Subject: [PATCH 024/267] UI: Code cleanup --- ui-ngx/src/app/shared/components/value-input.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/value-input.component.ts b/ui-ngx/src/app/shared/components/value-input.component.ts index 52828cec35..6d57b1ddd2 100644 --- a/ui-ngx/src/app/shared/components/value-input.component.ts +++ b/ui-ngx/src/app/shared/components/value-input.component.ts @@ -15,7 +15,7 @@ /// import { Component, forwardRef, Input, OnInit, ViewChild } from '@angular/core'; -import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm, NgModel } from '@angular/forms'; +import { ControlValueAccessor, NG_VALUE_ACCESSOR, NgForm } from '@angular/forms'; import { ValueType, valueTypesMap } from '@shared/models/constants'; import { isObject } from '@core/utils'; import { MatDialog } from '@angular/material/dialog'; @@ -23,7 +23,6 @@ import { JsonObjectEditDialogComponent, JsonObjectEditDialogData } from '@shared/components/dialog/json-object-edit-dialog.component'; -import { coerceBoolean } from '@shared/decorators/coercion'; @Component({ selector: 'tb-value-input', From 400752615552ba660505f9cff6836ca2394b1d5e Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Tue, 12 Sep 2023 15:39:57 +0300 Subject: [PATCH 025/267] Add init edge instructions for ubuntu and centos --- .../centos/instructions.md | 197 ++++++++++++++++++ .../docker/instructions.md | 4 +- .../ubuntu/instructions.md | 125 +++++++++++ .../server/controller/EdgeController.java | 6 +- .../DefaultEdgeInstallService.java | 50 ++++- .../edge/instructions/EdgeInstallService.java | 3 +- .../data/edge/EdgeInstallInstructions.java | 4 +- 7 files changed, 372 insertions(+), 17 deletions(-) create mode 100644 application/src/main/data/json/edge/install_instructions/centos/instructions.md create mode 100644 application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/install_instructions/centos/instructions.md new file mode 100644 index 0000000000..d42ce4499e --- /dev/null +++ b/application/src/main/data/json/edge/install_instructions/centos/instructions.md @@ -0,0 +1,197 @@ +## Install ThingsBoard Edge on CentOS/RHEL Server + +Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the cloud. + +### Prerequisites +Before continue to installation execute the following commands in order to install necessary tools: + +```bash +sudo yum install -y nano wget +sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm +``` + +### Install Java 11 (OpenJDK) +ThingsBoard service is running on Java 11. Follow this instructions to install OpenJDK 11: + +```bash +sudo yum install java-11-openjdk +``` +{: .copy-code} + +Please don't forget to configure your operating system to use OpenJDK 11 by default. +You can configure which version is the default using the following command: + +```bash +sudo update-alternatives --config java +``` +{: .copy-code} + +You can check the installation using the following command: + +```bash +java -version +``` +{: .copy-code} + +Expected command output is: + +```text +openjdk version "11.0.xx" +OpenJDK Runtime Environment (...) +OpenJDK 64-Bit Server VM (build ...) +``` + +### Configure PostgreSQL +ThingsBoard Edge uses PostgreSQL database as a local storage. +Instructions listed below will help you to install PostgreSQL. + +```bash +# Update your system +sudo yum update +``` +{: .copy-code} + +**For CentOS 7:** + +```bash +# Install the repository RPM (for CentOS 7): +sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-7-x86_64/pgdg-redhat-repo-latest.noarch.rpm +# Install packages +sudo yum -y install epel-release yum-utils +sudo yum-config-manager --enable pgdg12 +sudo yum install postgresql12-server postgresql12 +# Initialize your PostgreSQL DB +sudo /usr/pgsql-12/bin/postgresql-12-setup initdb +sudo systemctl start postgresql-12 +# Optional: Configure PostgreSQL to start on boot +sudo systemctl enable --now postgresql-12 + +``` +{: .copy-code} + +**For CentOS 8:** + +```bash +# Install the repository RPM (for CentOS 8): +sudo yum -y install https://download.postgresql.org/pub/repos/yum/reporpms/EL-8-x86_64/pgdg-redhat-repo-latest.noarch.rpm +# Install packages +sudo dnf -qy module disable postgresql +sudo dnf -y install postgresql12 postgresql12-server +# Initialize your PostgreSQL DB +sudo /usr/pgsql-12/bin/postgresql-12-setup initdb +sudo systemctl start postgresql-12 +# Optional: Configure PostgreSQL to start on boot +sudo systemctl enable --now postgresql-12 + +``` +{: .copy-code} + +Once PostgreSQL is installed you may want to create a new user or set the password for the the main user. +The instructions below will help to set the password for main postgresql user + +```text +sudo su - postgres +psql +\password +\q +``` + +Then, press "Ctrl+D" to return to main user console. + +After configuring the password, edit the pg_hba.conf to use MD5 authentication with the postgres user. + +Edit pg_hba.conf file: + +```bash +sudo nano /var/lib/pgsql/12/data/pg_hba.conf +``` +{: .copy-code} + +Locate the following lines: + +```text +# IPv4 local connections: +host all all 127.0.0.1/32 ident +``` + +Replace `ident` with `md5`: + +```text +host all all 127.0.0.1/32 md5 +``` + +Finally, you should restart the PostgreSQL service to initialize the new configuration: + +```bash +sudo systemctl restart postgresql-12.service +``` +{: .copy-code} + +Connect to the database to create ThingsBoard Edge DB: + +```bash +psql -U postgres -d postgres -h 127.0.0.1 -W +``` +{: .copy-code} + +Execute create database statement + +```bash +CREATE DATABASE tb_edge; +\q +``` +{: .copy-code} + +### ThingsBoard Edge service installation +Download installation package. + +```bash +wget https://github.com/thingsboard/thingsboard-edge/releases/download/{{ site.release.edge_tag }}/tb-edge-{{ site.release.edge_ver }}.rpm +``` +{: .copy-code} + +Go to the download repository and install ThingsBoard Edge service + +```bash +sudo rpm -Uvh tb-edge-${TB_EDGE_VERSION}.rpm +``` +{: .copy-code} + +### Configure ThingsBoard Edge + + +#### [Optional] Update bind ports +If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update docker compose port mapping to avoid port collision between ThingsBoard server and ThingsBoard Edge. + +Please update next lines of `docker-compose.yml` file: + +```bash +ports: + - "18080:8080" + - "11883:1883" + - "15683-15688:5683-5688/udp" +``` +Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. + +#### Run installation script +Once ThingsBoard Edge is installed and configured please execute the following install script: + +```bash +sudo /usr/share/tb-edge/bin/install/install.sh +``` +{: .copy-code} + +### Restart ThingsBoard Edge service + +```bash +sudo service tb-edge restart +``` + +#### Open ThingsBoard Edge UI + +Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080. + +###### NOTE: Edge HTTP bind port update + +Use next **ThingsBoard Edge UI** link **http://localhost:18080** if you updated HTTP 8080 bind port to **18080**. + diff --git a/application/src/main/data/json/edge/install_instructions/docker/instructions.md b/application/src/main/data/json/edge/install_instructions/docker/instructions.md index 6b93447851..14307dbea7 100644 --- a/application/src/main/data/json/edge/install_instructions/docker/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/docker/instructions.md @@ -1,6 +1,6 @@ -## Install ThingsBoard Edge and connect to cloud instructions +## Install ThingsBoard Edge using Docker -Here is the list of commands, that can be used to quickly install and connect ThingsBoard Edge to the cloud using docker compose. +Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the cloud. ### Prerequisites diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md new file mode 100644 index 0000000000..58df993bfa --- /dev/null +++ b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md @@ -0,0 +1,125 @@ +## Install ThingsBoard Edge on Ubuntu Server + +Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the cloud. + +### Install Java 11 (OpenJDK) +ThingsBoard service is running on Java 11. Follow this instructions to install OpenJDK 11: + +```bash +sudo apt update +sudo apt install openjdk-11-jdk +``` +{: .copy-code} + +Please don't forget to configure your operating system to use OpenJDK 11 by default. +You can configure which version is the default using the following command: + +```bash +sudo update-alternatives --config java +``` +{: .copy-code} + +You can check the installation using the following command: + +```bash +java -version +``` +{: .copy-code} + +Expected command output is: + +```text +openjdk version "11.0.xx" +OpenJDK Runtime Environment (...) +OpenJDK 64-Bit Server VM (build ...) +``` + +### Configure PostgreSQL +ThingsBoard Edge uses PostgreSQL database as a local storage. +Instructions listed below will help you to install PostgreSQL. + +```bash +# install **wget** if not already installed: +sudo apt install -y wget + +# import the repository signing key: +wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - + +# add repository contents to your system: +RELEASE=$(lsb_release -cs) +echo "deb http://apt.postgresql.org/pub/repos/apt/ ${RELEASE}"-pgdg main | sudo tee /etc/apt/sources.list.d/pgdg.list + +# install and launch the postgresql service: +sudo apt update +sudo apt -y install postgresql-12 +sudo service postgresql start +``` +{: .copy-code} + +Once PostgreSQL is installed you may want to create a new user or set the password for the the main user. +The instructions below will help to set the password for main postgresql user + +```text +sudo su - postgres +psql +\password +\q +``` + +Then, press “Ctrl+D” to return to main user console and connect to the database to create ThingsBoard Edge DB: + +```text +psql -U postgres -d postgres -h 127.0.0.1 -W +CREATE DATABASE tb_edge; +\q +``` + +### Thingsboard Edge service installation +Download installation package. + +```bash +wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.deb +``` +{: .copy-code} + +Go to the download repository and install ThingsBoard Edge service + +```bash +sudo dpkg -i tb-edge-{TB_EDGE_VERSION}.deb +{:copy-code} +``` + +Edit ThingsBoard Edge configuration file + +```bash +sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf +export HTTP_BIND_PORT=18080 +export MQTT_BIND_PORT=11883 +export COAP_BIND_PORT=15683 +export LWM2M_ENABLED=false +EOL' +{:copy-code} +``` + +#### Run installation script + +Once ThingsBoard Edge is installed and configured please execute the following install script: + +```bash +sudo /usr/share/tb-edge/bin/install/install.sh +``` + +#### Restart ThingsBoard Edge service + +```bash +sudo service tb-edge restart +``` + +#### Open ThingsBoard Edge UI + +Once started, you will be able to open **ThingsBoard Edge UI** using the following link http://localhost:8080. + +###### NOTE: Edge HTTP bind port update + +Use next **ThingsBoard Edge UI** link **http://localhost:18080** if you updated HTTP 8080 bind port to **18080**. + 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 a50f9c7658..2bc9c0e128 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -557,17 +557,19 @@ public class EdgeController extends BaseController { notes = "Get a docker install instructions for provided edge id." + TENANT_AUTHORITY_PARAGRAPH, produces = MediaType.APPLICATION_JSON_VALUE) @PreAuthorize("hasAnyAuthority('TENANT_ADMIN')") - @RequestMapping(value = "/edge/instructions/{edgeId}", method = RequestMethod.GET) + @RequestMapping(value = "/edge/instructions/{edgeId}/{method}", method = RequestMethod.GET) @ResponseBody public EdgeInstallInstructions getEdgeDockerInstallInstructions( @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId, + @ApiParam(value = "Installation method (e.g., 'docker', 'ubuntu', 'centos')") + @PathVariable("method") String installationMethod, HttpServletRequest request) throws ThingsboardException { if (isEdgesEnabled() && edgeInstallServiceOpt.isPresent()) { EdgeId edgeId = new EdgeId(toUUID(strEdgeId)); edgeId = checkNotNull(edgeId); Edge edge = checkEdgeId(edgeId, Operation.READ); - return checkNotNull(edgeInstallServiceOpt.get().getDockerInstallInstructions(getTenantId(), edge, request)); + return checkNotNull(edgeInstallServiceOpt.get().getInstallInstructions(getTenantId(), edge, installationMethod, request)); } else { throw new ThingsboardException("Edges support disabled", ThingsboardErrorCode.GENERAL); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java index 2c4a14635d..455b3e657a 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java @@ -28,7 +28,6 @@ import org.thingsboard.server.service.install.InstallScripts; import javax.servlet.http.HttpServletRequest; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -56,7 +55,20 @@ public class DefaultEdgeInstallService implements EdgeInstallService { private String appVersion; @Override - public EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request) { + public EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request) { + switch (installationMethod.toLowerCase()) { + case "docker": + return getDockerInstallInstructions(edge, request); + case "ubuntu": + return getUbuntuInstallInstructions(edge, request); + case "centos": + return getCentosInstallInstructions(edge, request); + default: + throw new IllegalArgumentException("Unsupported installation method for Edge: " + installationMethod); + } + } + + private EdgeInstallInstructions getDockerInstallInstructions(Edge edge, HttpServletRequest request) { String dockerInstallInstructions = readFile(resolveFile("docker", "instructions.md")); String baseUrl = request.getServerName(); if (baseUrl.contains("localhost") || baseUrl.contains("127.0.0.1")) { @@ -67,19 +79,39 @@ public class DefaultEdgeInstallService implements EdgeInstallService { dockerInstallInstructions = dockerInstallInstructions.replace("${LOCALHOST_WARNING}", ""); dockerInstallInstructions = dockerInstallInstructions.replace("${BASE_URL}", baseUrl); } + dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge); + return new EdgeInstallInstructions(dockerInstallInstructions); + } + + private EdgeInstallInstructions getUbuntuInstallInstructions(Edge edge, HttpServletRequest request) { + String ubuntuInstallInstructions = readFile(resolveFile("ubuntu", "instructions.md")); + ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge); + ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName()); + return new EdgeInstallInstructions(ubuntuInstallInstructions); + } + + + private EdgeInstallInstructions getCentosInstallInstructions(Edge edge, HttpServletRequest request) { + String centosInstallInstructions = readFile(resolveFile("centos", "instructions.md")); + centosInstallInstructions = replacePlaceholders(centosInstallInstructions, edge); + centosInstallInstructions = centosInstallInstructions.replace("${BASE_URL}", request.getServerName()); + return new EdgeInstallInstructions(centosInstallInstructions); + } + + private String replacePlaceholders(String instructions, Edge edge) { String edgeVersion = appVersion + "EDGE"; edgeVersion = edgeVersion.replace("-SNAPSHOT", ""); - dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); - dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey()); - dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret()); - dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort)); - dockerInstallInstructions = dockerInstallInstructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled)); - return new EdgeInstallInstructions(dockerInstallInstructions); + instructions = instructions.replace("${TB_EDGE_VERSION}", edgeVersion); + instructions = instructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey()); + instructions = instructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret()); + instructions = instructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort)); + instructions = instructions.replace("${CLOUD_RPC_SSL_ENABLED}", Boolean.toString(sslEnabled)); + return instructions; } private String readFile(Path file) { try { - return new String(Files.readAllBytes(file), StandardCharsets.UTF_8); + return Files.readString(file); } catch (IOException e) { log.warn("Failed to read file: {}", file, e); throw new RuntimeException(e); diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java index 2a030fc4fa..20cac25e33 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/EdgeInstallService.java @@ -23,6 +23,5 @@ import javax.servlet.http.HttpServletRequest; public interface EdgeInstallService { - EdgeInstallInstructions getDockerInstallInstructions(TenantId tenantId, Edge edge, HttpServletRequest request); - + EdgeInstallInstructions getInstallInstructions(TenantId tenantId, Edge edge, String installationMethod, HttpServletRequest request); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java index acfc458906..8343058250 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edge/EdgeInstallInstructions.java @@ -27,6 +27,6 @@ import lombok.NoArgsConstructor; @NoArgsConstructor public class EdgeInstallInstructions { - @ApiModelProperty(position = 1, value = "Markdown with docker install instructions") - private String dockerInstallInstructions; + @ApiModelProperty(position = 1, value = "Markdown with install instructions") + private String installInstructions; } From 8412b61812d947751b048aeaa0a2e7146d73c2d8 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Tue, 12 Sep 2023 16:33:30 +0300 Subject: [PATCH 026/267] Improve centos and ubuntu instruction for edge --- .../centos/instructions.md | 58 ++++++++++++++++--- .../docker/instructions.md | 2 +- .../ubuntu/instructions.md | 55 +++++++++++++++++- .../server/controller/EdgeController.java | 2 +- 4 files changed, 105 insertions(+), 12 deletions(-) diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/install_instructions/centos/instructions.md index d42ce4499e..3b0b823777 100644 --- a/application/src/main/data/json/edge/install_instructions/centos/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/centos/instructions.md @@ -158,21 +158,65 @@ sudo rpm -Uvh tb-edge-${TB_EDGE_VERSION}.rpm {: .copy-code} ### Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can either manually edit the configuration file or use a command to automate the process. +#### Automated Configuration +You can use the following command to automatically update the configuration file with specific values: + +```bash +sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf +export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} +export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} +export CLOUD_RPC_HOST=${BASE_URL} +export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED} +EOL' +``` +{: .copy-code} + +#### Manual Configuration + +```bash +sudo nano /etc/tb-edge/conf/tb-edge.conf +``` +{: .copy-code} + +Please update the following lines in your configuration file. Make sure to replace: + +```text +export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} +export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} +export CLOUD_RPC_HOST=${BASE_URL} +export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE + +``` #### [Optional] Update bind ports -If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update docker compose port mapping to avoid port collision between ThingsBoard server and ThingsBoard Edge. +If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. + +Please uncomment the following parameters in the ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): + +```text +export HTTP_BIND_PORT=18080 +export MQTT_BIND_PORT=11883 +export COAP_BIND_PORT=15683 +export LWM2M_ENABLED=false +``` -Please update next lines of `docker-compose.yml` file: +Or update using command: ```bash -ports: - - "18080:8080" - - "11883:1883" - - "15683-15688:5683-5688/udp" +sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf +export HTTP_BIND_PORT=18080 +export MQTT_BIND_PORT=11883 +export COAP_BIND_PORT=15683 +export LWM2M_ENABLED=false +EOL' ``` -Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. +{: .copy-code} +Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. #### Run installation script Once ThingsBoard Edge is installed and configured please execute the following install script: diff --git a/application/src/main/data/json/edge/install_instructions/docker/instructions.md b/application/src/main/data/json/edge/install_instructions/docker/instructions.md index 14307dbea7..d01986a831 100644 --- a/application/src/main/data/json/edge/install_instructions/docker/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/docker/instructions.md @@ -69,7 +69,7 @@ If ThingsBoard Edge is going to be running on the same machine where ThingsBoard Please update next lines of `docker-compose.yml` file: -```bash +```text ports: - "18080:8080" - "11883:1883" diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md index 58df993bfa..ab2bf6f8b4 100644 --- a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md @@ -86,10 +86,57 @@ Go to the download repository and install ThingsBoard Edge service ```bash sudo dpkg -i tb-edge-{TB_EDGE_VERSION}.deb -{:copy-code} ``` +{: .copy-code} + +### Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can either manually edit the configuration file or use a command to automate the process. + +#### Automated Configuration +You can use the following command to automatically update the configuration file with specific values: + +```bash +sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf +export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} +export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} +export CLOUD_RPC_HOST=${BASE_URL} +export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED} +EOL' +``` +{: .copy-code} + +#### Manual Configuration + +```bash +sudo nano /etc/tb-edge/conf/tb-edge.conf +``` +{: .copy-code} + +Please update the following lines in your configuration file. Make sure to replace: -Edit ThingsBoard Edge configuration file +```text +export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} +export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} +export CLOUD_RPC_HOST=${BASE_URL} +export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE + +``` + +#### [Optional] Update bind ports +If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. + +Please uncomment the following parameters in the ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): + +```text +export HTTP_BIND_PORT=18080 +export MQTT_BIND_PORT=11883 +export COAP_BIND_PORT=15683 +export LWM2M_ENABLED=false +``` + +Or update using command: ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -98,8 +145,10 @@ export MQTT_BIND_PORT=11883 export COAP_BIND_PORT=15683 export LWM2M_ENABLED=false EOL' -{:copy-code} ``` +{: .copy-code} + +Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. #### Run installation script 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 2bc9c0e128..fa16fbff81 100644 --- a/application/src/main/java/org/thingsboard/server/controller/EdgeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/EdgeController.java @@ -562,7 +562,7 @@ public class EdgeController extends BaseController { public EdgeInstallInstructions getEdgeDockerInstallInstructions( @ApiParam(value = EDGE_ID_PARAM_DESCRIPTION, required = true) @PathVariable("edgeId") String strEdgeId, - @ApiParam(value = "Installation method (e.g., 'docker', 'ubuntu', 'centos')") + @ApiParam(value = "Installation method ('docker', 'ubuntu' or 'centos')") @PathVariable("method") String installationMethod, HttpServletRequest request) throws ThingsboardException { if (isEdgesEnabled() && edgeInstallServiceOpt.isPresent()) { From 530cd326c09477ed222ef81d67d0bc2aad7c485c Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Tue, 12 Sep 2023 17:51:04 +0300 Subject: [PATCH 027/267] qa fixes --- .../json/demo/dashboards/gateway_list.json | 391 ++++++------------ .../gateway_general_statistics.json | 2 +- .../widget_types/gateway_statistics.json | 2 +- .../gateway-configuration.component.html | 6 +- .../gateway-configuration.component.scss | 8 + .../gateway-configuration.component.ts | 53 +-- .../lib/gateway/gateway-logs.component.html | 4 +- .../gateway/gateway-statistics.component.ts | 10 +- .../gateway-logs-settings.component.ts | 4 +- .../components/file-input.component.scss | 6 + .../assets/locale/locale.constant-en_US.json | 6 +- 11 files changed, 178 insertions(+), 314 deletions(-) diff --git a/application/src/main/data/json/demo/dashboards/gateway_list.json b/application/src/main/data/json/demo/dashboards/gateway_list.json index 7abee6cbe4..9adba7135a 100644 --- a/application/src/main/data/json/demo/dashboards/gateway_list.json +++ b/application/src/main/data/json/demo/dashboards/gateway_list.json @@ -7,13 +7,7 @@ "description": "", "widgets": { "23b9adc5-b3bd-040f-e5eb-a45925c73257": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -50,7 +44,8 @@ "enableSearch": true, "enableSelectColumnDisplay": false, "enableStickyHeader": true, - "enableStickyAction": true, + "enableStickyAction": false, + "showCellActionsMenu": true, "reserveSpaceForHiddenAction": "true", "displayEntityName": false, "displayEntityLabel": false, @@ -249,16 +244,11 @@ }, "row": 0, "col": 0, - "id": "23b9adc5-b3bd-040f-e5eb-a45925c73257" + "id": "23b9adc5-b3bd-040f-e5eb-a45925c73257", + "typeFullFqn": "system.cards.entities_table" }, "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_configuration2", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 6, "config": { @@ -319,16 +309,11 @@ }, "row": 0, "col": 0, - "id": "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99" + "id": "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99", + "typeFullFqn": "system.gateway_widgets.gateway_configuration2" }, "02a05113-d878-b086-328e-75bd6f02b2bb": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_connector", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 11, "sizeY": 8, "config": { @@ -398,16 +383,11 @@ }, "row": 0, "col": 0, - "id": "02a05113-d878-b086-328e-75bd6f02b2bb" + "id": "02a05113-d878-b086-328e-75bd6f02b2bb", + "typeFullFqn": "system.gateway_widgets.gateway_connector" }, "79f59106-758f-c428-8b93-4341faea705d": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -558,9 +538,9 @@ "padding": "8px", "settings": { "useMarkdownTextFunction": true, - "markdownTextFunction": "var blockData = '';\nfunction createDataBlock(value, label, dividerStyle, mobile) {\n blockData += `\n \n
\n \n \n ${label}\n \n ${value}\n
`;\n}\ncreateDataBlock(data[0].Status, \"Status\", data[0].Status === \"Active\"? 'divider-green' : 'divider-red');\ncreateDataBlock(data[0].Name, \"Gateway Name\", '', ctx.isMobile);\ncreateDataBlock(data[0].Type, \"Gateway Type\", '');\ncreateDataBlock(\n `${(data[1]?data[1].count:0)} `\n + \" | \" + \n `${(data[2]?data[2][\"count 2\"]:0)} `\n , \"Devices\", '');\ncreateDataBlock(\n `${(data[0].active_connectors?JSON.parse(data[0].active_connectors).length:0)} `\n + \" | \" + \n `${(data[0].inactive_connectors?JSON.parse(data[0].inactive_connectors).length:0)} `\n , \"Connectors\", '');\ncreateDataBlock(data[0].ALL_ERRORS_COUNT || 0, \"Errors\", (data[0].ALL_ERRORS_COUNT || 0) === 0 ? 'divider-green' : 'divider-red');\nreturn `
${blockData}
`;", + "markdownTextFunction": "var blockData = '';\nvar connectorsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Connecotrs\");\nvar logsIndex = ctx.actionsApi.getActionDescriptors('elementClick').findIndex(action=>action.name==\"Logs\");\nfunction generateMatHeader(index) {\n if( index !== undefined && index > -1) {\n return ``\n } else {\n return \"\" \n }\n}\nfunction createDataBlock(value, label, dividerStyle, mobile, index) {\n blockData += `\n \n
\n \n ${generateMatHeader(index)}\n ${label}\n
\n ${value}\n `;\n}\ncreateDataBlock(data[0].Status, \"Status\", data[0].Status === \"Active\"? 'divider-green' : 'divider-red');\ncreateDataBlock(data[0].Name, \"Gateway Name\", '', ctx.isMobile);\ncreateDataBlock(data[0].Type, \"Gateway Type\", '');\ncreateDataBlock(\n `${(data[1]?data[1].count:0)} `\n + \" | \" + \n `${(data[2]?data[2][\"count 2\"]:0)} `\n , \"Devices (Active | Inactive)\", '');\ncreateDataBlock(\n `${(data[0].active_connectors?JSON.parse(data[0].active_connectors).length:0)} `\n + \" | \" + \n `${(data[0].inactive_connectors?JSON.parse(data[0].inactive_connectors).length:0)} `\n , \"Connectors (Active | Inactive)\", '', '', connectorsIndex);\ncreateDataBlock(data[0].ALL_ERRORS_COUNT || 0, \"Errors\", (data[0].ALL_ERRORS_COUNT || 0) === 0 ? 'divider-green' : 'divider-red', '', logsIndex);\nreturn `
${blockData}
`;", "applyDefaultMarkdownStyle": false, - "markdownCss": ".divider {\n position: absolute;\n width: 3px;\n top: 8px;\n border-radius: 2px;\n bottom: 8px;\n border: 1px solid rgba(31, 70, 144, 1);\n background-color: rgba(31, 70, 144, 1);\n left: 10px;\n}\n.divider-green .divider {\n border: 1px solid rgb(25,128,56);\n background-color: rgb(25,128,56);\n}\n\n.divider-green .mat-mdc-card-content {\n color: rgb(25,128,56);\n}\n\n.divider-red .divider {\n border: 1px solid rgb(203,37,48);\n background-color: rgb(203,37,48);\n}\n\n.divider-red .mat-mdc-card-content {\n color: rgb(203,37,48);\n}\n\n.mdc-card {\n position: relative;\n padding-left: 10px;\n margin-bottom: 1px;\n}\n\n.mat-mdc-card-subtitle {\n font-weight: 400;\n font-size: 12px;\n}\n\n.mat-mdc-card-header {\n padding: 8px 16px 0;\n}\n\n.mat-mdc-card-content:last-child {\n padding-bottom: 8px;\n font-size: 16px;\n}\n\n.cards-container {\n height: calc(100% - 1px);\n justify-content: stretch;\n align-items: center;\n margin-bottom: 1px;\n}" + "markdownCss": ".divider {\n position: absolute;\n width: 3px;\n top: 8px;\n border-radius: 2px;\n bottom: 8px;\n border: 1px solid rgba(31, 70, 144, 1);\n background-color: rgba(31, 70, 144, 1);\n left: 10px;\n}\n.divider-green .divider {\n border: 1px solid rgb(25,128,56);\n background-color: rgb(25,128,56);\n}\n\n.divider-green .mat-mdc-card-content {\n color: rgb(25,128,56);\n}\n\n.divider-red .divider {\n border: 1px solid rgb(203,37,48);\n background-color: rgb(203,37,48);\n}\n\n.divider-red .mat-mdc-card-content {\n color: rgb(203,37,48);\n}\n\n.mdc-card {\n position: relative;\n padding-left: 10px;\n margin-bottom: 1px;\n}\n\n.mat-mdc-card-subtitle {\n font-weight: 400;\n font-size: 12px;\n}\n\n.mat-mdc-card-header {\n padding: 8px 16px 0;\n}\n\n.mat-mdc-card-content:last-child {\n padding-bottom: 8px;\n font-size: 16px;\n}\n\n.cards-container {\n height: calc(100% - 1px);\n justify-content: stretch;\n align-items: center;\n margin-bottom: 1px;\n}\n\n::ng-deep.tb-home-widget-link > div {\n flex-grow: 1;\n cursor: pointer;\n}\n\n .tb-home-widget-link {\n width: 100%;\n }\n\n .tb-home-widget-link:hover::after{\n color: inherit;\n }\n \n .tb-home-widget-link::after{\n content: 'arrow_forward';\n display: inline-block;\n transform: rotate(315deg);\n font-family: 'Material Icons';\n font-weight: normal;\n font-style: normal;\n font-size: 18px;\n color: rgba(0, 0, 0, 0.12);\n vertical-align: bottom;\n margin-left: 6px;\n}" }, "title": "New Markdown/HTML Card", "showTitleIcon": false, @@ -583,20 +563,47 @@ "pageSize": 1024, "noDataDisplayMessage": "", "enableDataExport": false, - "displayTimewindow": true + "displayTimewindow": true, + "actions": { + "elementClick": [ + { + "name": "Connecotrs", + "icon": "more_horiz", + "useShowWidgetActionFunction": null, + "showWidgetActionFunction": "return true;", + "type": "openDashboardState", + "targetDashboardStateId": "connectors", + "setEntityId": true, + "stateEntityParamName": null, + "openRightLayout": false, + "openInSeparateDialog": false, + "openInPopover": false, + "id": "ee7216d8-ad7a-20db-1abc-2531e221f24c" + }, + { + "name": "Logs", + "icon": "more_horiz", + "useShowWidgetActionFunction": null, + "showWidgetActionFunction": "return true;", + "type": "openDashboardState", + "targetDashboardStateId": "logs", + "setEntityId": true, + "stateEntityParamName": null, + "openRightLayout": false, + "openInSeparateDialog": false, + "openInPopover": false, + "id": "ceec0446-c25f-2b9b-b1b1-58ed751476ff" + } + ] + } }, "row": 0, "col": 0, - "id": "79f59106-758f-c428-8b93-4341faea705d" + "id": "79f59106-758f-c428-8b93-4341faea705d", + "typeFullFqn": "system.cards.markdown_card" }, "60dcf518-8fc3-3539-8ff8-ce94bda39f3a": { - "isSystemType": true, - "bundleAlias": "alarm_widgets", - "typeAlias": "alarms_table", "type": "alarm", - "title": "New widget", - "image": null, - "description": null, "sizeX": 10.5, "sizeY": 6.5, "config": { @@ -737,16 +744,11 @@ }, "row": 0, "col": 0, - "id": "60dcf518-8fc3-3539-8ff8-ce94bda39f3a" + "id": "60dcf518-8fc3-3539-8ff8-ce94bda39f3a", + "typeFullFqn": "system.alarm_widgets.alarms_table" }, "27e6b37c-085e-824d-fb13-69651a545ec1": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_logs", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 3, "config": { @@ -784,7 +786,7 @@ "color": "rgba(0, 0, 0, 0.87)", "padding": "8px", "settings": {}, - "title": "Gateway Logs", + "title": "Logs", "showTitleIcon": false, "dropShadow": false, "enableFullscreen": true, @@ -806,16 +808,11 @@ }, "row": 0, "col": 0, - "id": "27e6b37c-085e-824d-fb13-69651a545ec1" + "id": "27e6b37c-085e-824d-fb13-69651a545ec1", + "typeFullFqn": "system.gateway_widgets.gateway_logs" }, "bcd04dbf-c82a-ca13-6e88-a74f32b4348a": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_logs", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 3, "config": { @@ -878,16 +875,11 @@ }, "row": 0, "col": 0, - "id": "bcd04dbf-c82a-ca13-6e88-a74f32b4348a" + "id": "bcd04dbf-c82a-ca13-6e88-a74f32b4348a", + "typeFullFqn": "system.gateway_widgets.gateway_logs" }, "9b88dc51-b186-90ef-5afb-9648e6e2ac9a": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_statistics", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 5, "config": { @@ -973,7 +965,7 @@ "customLegendEnabled": false, "dataKeysListForLabels": [] }, - "title": "Statistics", + "title": "Gateway Custom Statistics", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -1005,16 +997,11 @@ }, "row": 0, "col": 0, - "id": "9b88dc51-b186-90ef-5afb-9648e6e2ac9a" + "id": "9b88dc51-b186-90ef-5afb-9648e6e2ac9a", + "typeFullFqn": "system.gateway_widgets.gateway_statistics" }, "2a318e56-5c83-4f82-bf23-df72dd7e3edf": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_remote_shell", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1083,16 +1070,11 @@ }, "row": 0, "col": 0, - "id": "2a318e56-5c83-4f82-bf23-df72dd7e3edf" + "id": "2a318e56-5c83-4f82-bf23-df72dd7e3edf", + "typeFullFqn": "system.control_widgets.rpc_remote_shell" }, "c50e294a-265a-d13c-c772-b56c4df953fe": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_general_statistics", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 5, "config": { @@ -1272,7 +1254,7 @@ "customLegendEnabled": false, "dataKeysListForLabels": [] }, - "title": "General Statistics", + "title": "Gateway General Chart Statistics", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -1304,16 +1286,11 @@ }, "row": 0, "col": 0, - "id": "c50e294a-265a-d13c-c772-b56c4df953fe" + "id": "c50e294a-265a-d13c-c772-b56c4df953fe", + "typeFullFqn": "system.gateway_widgets.gateway_general_statistics" }, "da01e13f-c108-39fd-2a74-b40da088769a": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "timeseries_table", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 6.5, "config": { @@ -1433,16 +1410,11 @@ }, "row": 0, "col": 0, - "id": "da01e13f-c108-39fd-2a74-b40da088769a" + "id": "da01e13f-c108-39fd-2a74-b40da088769a", + "typeFullFqn": "system.cards.timeseries_table" }, "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_debug_terminal", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1512,16 +1484,11 @@ }, "row": 0, "col": 0, - "id": "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f" + "id": "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f", + "typeFullFqn": "system.control_widgets.rpc_debug_terminal" }, "46b68eb5-7e2d-bca1-c2ef-061b64575218": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "service_rpc", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 4, "sizeY": 2, "config": { @@ -1590,16 +1557,11 @@ }, "row": 0, "col": 0, - "id": "46b68eb5-7e2d-bca1-c2ef-061b64575218" + "id": "46b68eb5-7e2d-bca1-c2ef-061b64575218", + "typeFullFqn": "system.gateway_widgets.service_rpc" }, "878c68fd-71cb-21d4-684a-b5b5a4526b43": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "service_rpc", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 4, "sizeY": 2, "config": { @@ -1635,16 +1597,11 @@ }, "row": 0, "col": 0, - "id": "878c68fd-71cb-21d4-684a-b5b5a4526b43" + "id": "878c68fd-71cb-21d4-684a-b5b5a4526b43", + "typeFullFqn": "system.gateway_widgets.service_rpc" }, "0fc7dcf3-32a2-0159-738e-96956bf0d450": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "timeseries_table", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 6.5, "config": { @@ -1765,16 +1722,11 @@ }, "row": 0, "col": 0, - "id": "0fc7dcf3-32a2-0159-738e-96956bf0d450" + "id": "0fc7dcf3-32a2-0159-738e-96956bf0d450", + "typeFullFqn": "system.cards.timeseries_table" }, "6e136fbc-545b-4926-c0a9-79348f35628a": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_debug_terminal", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1844,16 +1796,11 @@ }, "row": 0, "col": 0, - "id": "6e136fbc-545b-4926-c0a9-79348f35628a" + "id": "6e136fbc-545b-4926-c0a9-79348f35628a", + "typeFullFqn": "system.control_widgets.rpc_debug_terminal" }, "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -1896,7 +1843,7 @@ "padding": "8px", "settings": { "useMarkdownTextFunction": false, - "markdownTextPattern": "
\r\n\r\n
", + "markdownTextPattern": "
\r\n\r\n
", "applyDefaultMarkdownStyle": false, "markdownCss": ".action-buttons-container {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex-direction: row;\r\n height: 100%;\r\n width: 100%;\r\n align-content: center;\r\n}\r\n\r\nbutton {\r\n flex-grow: 1;\r\n margin: 10px;\r\n min-width: 150px;\r\n height: auto;\r\n}" }, @@ -1945,16 +1892,11 @@ }, "row": 0, "col": 0, - "id": "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19" + "id": "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19", + "typeFullFqn": "system.cards.markdown_card" }, "61d149e8-b249-5526-e5d7-6ad58413982e": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -2129,16 +2071,11 @@ }, "row": 0, "col": 0, - "id": "61d149e8-b249-5526-e5d7-6ad58413982e" + "id": "61d149e8-b249-5526-e5d7-6ad58413982e", + "typeFullFqn": "system.cards.markdown_card" }, "3d661190-7463-ba61-6793-503c85af67ec": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -2213,16 +2150,11 @@ }, "row": 0, "col": 0, - "id": "3d661190-7463-ba61-6793-503c85af67ec" + "id": "3d661190-7463-ba61-6793-503c85af67ec", + "typeFullFqn": "system.cards.markdown_card" }, "1615bd4e-c0a4-c32c-3706-3c83214cb8d7": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2371,16 +2303,11 @@ }, "row": 0, "col": 0, - "id": "1615bd4e-c0a4-c32c-3706-3c83214cb8d7" + "id": "1615bd4e-c0a4-c32c-3706-3c83214cb8d7", + "typeFullFqn": "system.cards.entities_table" }, "aafba3d8-a381-21c0-ecbe-446da3cdc041": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2529,16 +2456,11 @@ }, "row": 0, "col": 0, - "id": "aafba3d8-a381-21c0-ecbe-446da3cdc041" + "id": "aafba3d8-a381-21c0-ecbe-446da3cdc041", + "typeFullFqn": "system.cards.entities_table" }, "7f676bb2-bde2-10e7-80d8-25dd734e8e22": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2687,16 +2609,11 @@ }, "row": 0, "col": 0, - "id": "7f676bb2-bde2-10e7-80d8-25dd734e8e22" + "id": "7f676bb2-bde2-10e7-80d8-25dd734e8e22", + "typeFullFqn": "system.cards.entities_table" }, "d64482d8-001a-6f33-9b56-665530098fe5": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2845,16 +2762,11 @@ }, "row": 0, "col": 0, - "id": "d64482d8-001a-6f33-9b56-665530098fe5" + "id": "d64482d8-001a-6f33-9b56-665530098fe5", + "typeFullFqn": "system.cards.entities_table" }, "bb27723a-989c-2327-5808-b56d490b93ab": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3003,16 +2915,11 @@ }, "row": 0, "col": 0, - "id": "bb27723a-989c-2327-5808-b56d490b93ab" + "id": "bb27723a-989c-2327-5808-b56d490b93ab", + "typeFullFqn": "system.cards.entities_table" }, "e3a9539d-2ccb-96e0-2afa-36f93e40233d": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3161,16 +3068,11 @@ }, "row": 0, "col": 0, - "id": "e3a9539d-2ccb-96e0-2afa-36f93e40233d" + "id": "e3a9539d-2ccb-96e0-2afa-36f93e40233d", + "typeFullFqn": "system.cards.entities_table" }, "cf2eba6b-44f6-9cc2-6089-35c735f54898": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3319,16 +3221,11 @@ }, "row": 0, "col": 0, - "id": "cf2eba6b-44f6-9cc2-6089-35c735f54898" + "id": "cf2eba6b-44f6-9cc2-6089-35c735f54898", + "typeFullFqn": "system.cards.entities_table" }, "3f6ed61b-f5af-13e3-7505-f69fd53f8211": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3477,16 +3374,11 @@ }, "row": 0, "col": 0, - "id": "3f6ed61b-f5af-13e3-7505-f69fd53f8211" + "id": "3f6ed61b-f5af-13e3-7505-f69fd53f8211", + "typeFullFqn": "system.cards.entities_table" }, "b06cecaa-2806-65a9-782d-4f2d8cf95a6c": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3635,16 +3527,11 @@ }, "row": 0, "col": 0, - "id": "b06cecaa-2806-65a9-782d-4f2d8cf95a6c" + "id": "b06cecaa-2806-65a9-782d-4f2d8cf95a6c", + "typeFullFqn": "system.cards.entities_table" }, "c3d39b60-a668-7f5e-e6f4-cae27151f4aa": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3793,16 +3680,11 @@ }, "row": 0, "col": 0, - "id": "c3d39b60-a668-7f5e-e6f4-cae27151f4aa" + "id": "c3d39b60-a668-7f5e-e6f4-cae27151f4aa", + "typeFullFqn": "system.cards.entities_table" }, "f78a0d66-60cb-188f-857f-9acd4d24bd5a": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3951,16 +3833,11 @@ }, "row": 0, "col": 0, - "id": "f78a0d66-60cb-188f-857f-9acd4d24bd5a" + "id": "f78a0d66-60cb-188f-857f-9acd4d24bd5a", + "typeFullFqn": "system.cards.entities_table" }, "b81a171c-77c0-b857-21d2-cff02a1cb733": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4109,16 +3986,11 @@ }, "row": 0, "col": 0, - "id": "b81a171c-77c0-b857-21d2-cff02a1cb733" + "id": "b81a171c-77c0-b857-21d2-cff02a1cb733", + "typeFullFqn": "system.cards.entities_table" }, "0e399bef-01d2-4e4e-02d2-e254ebe91e56": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4267,16 +4139,11 @@ }, "row": 0, "col": 0, - "id": "0e399bef-01d2-4e4e-02d2-e254ebe91e56" + "id": "0e399bef-01d2-4e4e-02d2-e254ebe91e56", + "typeFullFqn": "system.cards.entities_table" }, "819c1d39-de7c-8ac3-858e-0040d286823e": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4425,16 +4292,11 @@ }, "row": 0, "col": 0, - "id": "819c1d39-de7c-8ac3-858e-0040d286823e" + "id": "819c1d39-de7c-8ac3-858e-0040d286823e", + "typeFullFqn": "system.cards.entities_table" }, "d4f73f32-f719-98bb-d427-b5c8957e8f47": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4583,16 +4445,11 @@ }, "row": 0, "col": 0, - "id": "d4f73f32-f719-98bb-d427-b5c8957e8f47" + "id": "d4f73f32-f719-98bb-d427-b5c8957e8f47", + "typeFullFqn": "system.cards.entities_table" }, "f16a258c-3f6c-9317-fda7-48b33d8fe8b9": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4741,16 +4598,11 @@ }, "row": 0, "col": 0, - "id": "f16a258c-3f6c-9317-fda7-48b33d8fe8b9" + "id": "f16a258c-3f6c-9317-fda7-48b33d8fe8b9", + "typeFullFqn": "system.cards.entities_table" }, "d1951ec7-ab13-87e4-bc05-ce2318dca353": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4899,16 +4751,11 @@ }, "row": 0, "col": 0, - "id": "d1951ec7-ab13-87e4-bc05-ce2318dca353" + "id": "d1951ec7-ab13-87e4-bc05-ce2318dca353", + "typeFullFqn": "system.cards.entities_table" }, "75b6372d-4def-42b4-8774-4edf413a8b83": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -5057,16 +4904,11 @@ }, "row": 0, "col": 0, - "id": "75b6372d-4def-42b4-8774-4edf413a8b83" + "id": "75b6372d-4def-42b4-8774-4edf413a8b83", + "typeFullFqn": "system.cards.entities_table" }, "dfda1a57-6c04-3482-2054-84954bbef626": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -5152,7 +4994,8 @@ }, "row": 0, "col": 0, - "id": "dfda1a57-6c04-3482-2054-84954bbef626" + "id": "dfda1a57-6c04-3482-2054-84954bbef626", + "typeFullFqn": "system.cards.markdown_card" } }, "states": { diff --git a/application/src/main/data/json/system/widget_types/gateway_general_statistics.json b/application/src/main/data/json/system/widget_types/gateway_general_statistics.json index 8cf20c1340..977e09aa7d 100644 --- a/application/src/main/data/json/system/widget_types/gateway_general_statistics.json +++ b/application/src/main/data/json/system/widget_types/gateway_general_statistics.json @@ -1,6 +1,6 @@ { "fqn": "gateway_widgets.gateway_general_statistics", - "name": "Gateway General Statistics", + "name": "Gateway General Chart Statistics", "deprecated": false, "image": "data:image/png;base64,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", "description": "", diff --git a/application/src/main/data/json/system/widget_types/gateway_statistics.json b/application/src/main/data/json/system/widget_types/gateway_statistics.json index 1eb24c4482..198591b6dc 100644 --- a/application/src/main/data/json/system/widget_types/gateway_statistics.json +++ b/application/src/main/data/json/system/widget_types/gateway_statistics.json @@ -1,6 +1,6 @@ { "fqn": "gateway_widgets.gateway_statistics", - "name": "Gateway statistics", + "name": "Gateway Custom Statistics", "deprecated": false, "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAkACQAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAFSBl0DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKBwKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiimyLvQ84PY0AOoqKyn+02sb/3lBqWgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooqlr0rR2IwcbmAP05oWrAu0Vy9FachPMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvQrFTkcH1FHIHMdRRUdo5ktY2PUoCfyqSsyiro3/ILg/wBwfyq1VXRv+QXB/uD+VWqACiiigAooqj4l8S6d4M8PX2r6xf2WlaTpkD3V5e3k6wW9pCilnkkkYhURVBJYkAAEmhuyuwSbdkXqK8l8H/t8/Ar4h+KLLRPD/wAafhNrutanKILPT9O8X6fdXV3IeiRxJKXdj6KCa7z4ZfEzQvjJ4D03xP4Z1GLVtC1iLzrO8iVlSdMlcgMAeoI5HajXcV1exvUUUUDCiqPiXxLp3gzw9favrF/ZaVpWmQPdXl7eTrBb2kKKWeSSRiFRFUEliQAASasafqEGrWEN1azRXNtcxrLDNE4eOVGGVZWHBBBBBHXNAE1FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUVg6n8UvDOiePtM8KXniLQrTxRrUElzp+jzX8Ud/fxR8ySRQFvMkVP4mVSB3o62Dpc3qKw7v4neG7D4g2nhKfxDocPiq/tHv7XRpL+JdQubZDteZIC3mNGp4LhcA963KOlw62CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACqHiH/jyX/fH8jV+qHiH/AI8l/wB8fyNOO4nsY1cx8YfEOq+Fvh/eXujQST3kTRgmO1a6eGIyKJJVhX5pGRCzBBySOh6V09ZXjPw1J4r0M20Go3mlXCyJNDdWxG+N0YMMg5DKcYKnggkVuQeUx/HvV9I8Dw6npl1pvj2zutesdLgu7XZbzxpNKkcqXERZAkyFiAOPvLuUYOe71b4wQ6J4zttJudJ1WKO7ulsYr11jWF5mjLhVBfey8Ebwu3IIzxWJP+zudQtNWnu9euJdc1fUrHU5L2O0jjjjezZGhRYRxt+T5ssWO4/MMABNQ/Zug1D4nR+I21VsxapHqyxNYwvKJFj8sxidgXWIjkKuMHPJHFICt4S+O+o+IdN0KbUdOl0aXU/FF5oix+XHOJ0h+1YOVlynEAy3zfMDhcHIl/4aObXfhzrWvaL4e1W4jsbCW9s3laDyrrYSCpxLmNhjJR9rYB4yMVoWHwHjtH09X1a5lt9K8QXGv2qeUqsjTrPviLDqA1w5BwCMAc9ap6J+zfDp9xq0l1rNzeSanpkulGYW0UMzxv1kndR+/mGAA7AcZ4ySaAHy/HlNE1TUf7Ut7yD7Ho+nXp09LdHl866mliSNZFlIdmdFXbgAcHecnb1/g7xZN4ojuhc6Pqui3FnII3ivUX58qGDI6MyOvOPlY4IIOK5TUv2eodf+3y6hq91LfX+mWFibmGFIjBLZzSTRXCKdw3eY4O05HyDrk11Xgzw1f+H4rt9S1q51q7vJRIzvGsMUAChQkca8KvGTkkksTnoAwNuiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA6Ox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+VS1FY/8eUP+4v8AKpa5zQq6N/yC4P8AcH8qtVV0b/kFwf7g/lVqgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqh4h/48l/3x/I1frnPib420bwHoMV3rmraZo1pJcCFJ766S3jZyrEKGcgFsKxx1wD6U47iexFVTXdBsfFOjXWnanZWmo6fexNDc2t1Cs0NxGwwyOjAqykdQRiuW/4aP+Hn/Q+eDP8Awd23/wAXR/w0f8PP+h88Gf8Ag7tv/i63IJfBX7P/AID+G1j9m8O+CfCOgW32NtP8rTdHt7VPszMXaDbGgHlliSU+6SScVqaT8NfDmg3ul3FjoGiWdxodidM06WCxijfT7Q7M28JCgxxHy48ouF+ReOBWN/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0gMnwn+xl8HvAXjr/hKNC+FHw10XxN5rz/ANr2Hhiytr7zHOWfzkiD7mJyTnJNTan8Er/xR+0JpvjLWdfivNI8NW8q6BokOnCIWVzMgjmuppzIxmfZuRAqRhFkfO8kEaH/AA0f8PP+h88Gf+Du2/8Ai6P+Gj/h5/0Pngz/AMHdt/8AF0AbWtfDjw94k8WaVr2oaDot/rug+YNM1G5sYpbvTvMG2TyZWUvHuHB2kZHWs0fAfwOPicfG3/CGeFP+EzMfknX/AOyLf+0ymMbftOzzcY4xuxVf/ho/4ef9D54M/wDB3bf/ABdH/DR/w8/6HzwZ/wCDu2/+LoAn1f4CeBfEHxItPGN/4L8J3vi+wUJa65caRbyalbKOgS4ZDIo9g1N+Jv7P3gL41XVhP4y8EeEfFs2ltvspNa0e3v2s265jMqMUPuuKi/4aP+Hn/Q+eDP8Awd23/wAXR/w0f8PP+h88Gf8Ag7tv/i6ANbxx8LPD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JWk3M8QUlURi/wBX0UAeL/tl/GeX4IeHtGv9L8La5rXiTVbiTS7HVtN8Iah4jHhyN1DTXM0dhBNOI8IuEUASyCNSyrl15HxN4ZsPEH/BP06X4I07xlqEP2i12R6v4dvtL1e9mGpxSXM8tpcwQzqXfzZSfKVSCWX5cV9LUUAeV/G/xL4X+H1t4u8R3XgDW/Fms6PpFpeTR6b4Zn1G41ZYp5HtbeArGwmljm3OETc0W8OQMg186anaP8e/hHf681r8T7jxBN4r0jXvGMVt4N13w5cJYQEqlrpovbWCa4FuuH3QAzMyu6hHdEH2/RQB87fsv2URtoTrGkeO9S0KLxPK3gC58V2Go3esaZbHTwJJbmW8VruBS5u0R7wrIQ6qT8yg9Bpmh6npPxr+Nupnwzda3a32laV9htJYxHDrbR21wHgSSQeW2SVU5OAXG7Fe00UAfNn7L0uqeL/2mPEficL8QNR0W60VbX7R4y8ONodx4fnFxv8A7MskNtbCe2wSxl8uQlkT/SJRhU+k6KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACvkr9unwzrN78YftcVz8S/D2n33hSTSLa+8E+HJNcl16eSZy2nXwW3uBa2+NhEwFu372TF1Fjn61ooA+EvH/AMM/FXhPX9S1KXRvijo3jnV/C2iQ+C7bwfPqMmiadqFtavG9neNbE2/kxzMSf7RJgKSZQl91fSvxC8P6rqH7Snwk1D7DczwadZ6yt/cwws0Fq8kFuFDuBhdzBguSM4OOlesUUAeC/G3xodE+LXgH4gnQPGV/4d8NSa1ompR2Phy9vb60klESx3KWkUTXEsJa3ZBJFGwKzKw+Qlq6b9jTwvqfhb4E266tYXOl3Wp6tqurraXKbJ7eG71C4uYlkXqj+XKm5TypyDyK9UooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA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qf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCro3/ILg/3B/KrVVdG/wCQXB/uD+VWqACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK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J1KPzbe4QMu8ZIIKsAysCCCrAMpBBAIIrxz42+NDonxa8A/EE6B4yv8Aw74ak1rRNSjsfDl7e31pJKIljuUtIomuJYS1uyCSKNgVmVh8hLV037GnhfU/C3wJt11awudLutT1bVdXW0uU2T28N3qFxcxLIvVH8uVNynlTkHkUAeqUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAVdG/5BcH+4P5Vaqro3/ILg/3B/KrVABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAVdG/wCQXB/uD+VWqq6N/wAguD/cH8qtUAFFFFAF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UPtOqf8APnYf+Bj/APxqj7Tqn/PnYf8AgY//AMaq41wFpn2ugCt9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVZF1UizA0AUvtOqf8+dh/4GP/APGqPtOqf8+dh/4GP/8AGqvg5paACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAq6N/yC4P9wfyq1RRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFACHpUMxoooAqTGod1FFAChuasQmiigC1Ef51LRRQB//9k=", "description": null, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html index 6f8c675e6f..ed45f6e830 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html @@ -556,9 +556,9 @@
gateway.statistics.commands
gateway.hints.commands
-
-
+
gateway.statistics.attribute-name @@ -619,7 +619,7 @@
+ [class.no-padding-bottom]="gatewayConfigGroup.get('thingsboard.checkingDeviceActivity.checkDeviceInactivity').value">
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss index 803654734f..d15c05a902 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.scss @@ -45,6 +45,14 @@ .saving-period { flex: 1; } + + .statistics-container { + width: 50%; + + .command-container { + width: 100%; + } + } } :host ::ng-deep { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts index bef0c2cc74..ed64c96799 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts @@ -48,6 +48,7 @@ import { StorageTypes, StorageTypesTranslationMap } from './gateway-widget.models'; +import { deepTrim } from '@core/utils'; @Component({ selector: 'tb-gateway-configuration', @@ -91,7 +92,7 @@ export class GatewayConfigurationComponent implements OnInit { ngOnInit() { this.gatewayConfigGroup = this.fb.group({ thingsboard: this.fb.group({ - host: [window.location.hostname, [Validators.required]], + host: [window.location.hostname, [Validators.required, Validators.pattern(/^[^\s]+$/)]], port: [1883, [Validators.required, Validators.min(1), Validators.max(65535), Validators.pattern(/^-?[0-9]+$/)]], remoteShell: [false, []], remoteConfiguration: [true, []], @@ -107,30 +108,30 @@ export class GatewayConfigurationComponent implements OnInit { handleDeviceRenaming: [true, []], checkingDeviceActivity: this.fb.group({ checkDeviceInactivity: [false, []], - inactivityTimeoutSeconds: [200, [Validators.min(1)]], - inactivityCheckPeriodSeconds: [500, [Validators.min(1)]] + inactivityTimeoutSeconds: [200, [Validators.min(1), Validators.pattern(/^[^.\s]+$/)]], + inactivityCheckPeriodSeconds: [500, [Validators.min(1), Validators.pattern(/^[^.\s]+$/)]] }), security: this.fb.group({ type: [SecurityTypes.ACCESS_TOKEN, [Validators.required]], - accessToken: [null, [Validators.required]], - clientId: [null, []], - username: [null, []], - password: [null, []], + accessToken: [null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], + clientId: [null, [Validators.pattern(/^[^.\s]+$/)]], + username: [null, [Validators.pattern(/^[^.\s]+$/)]], + password: [null, [Validators.pattern(/^[^.\s]+$/)]], caCert: [null, []], cert: [null, []], privateKey: [null, []], }), - qos: [1, [Validators.min(0), Validators.max(1), Validators.required]] + qos: [1, [Validators.min(0), Validators.max(1), Validators.required, Validators.pattern(/^[^.\s]+$/)]] }), storage: this.fb.group({ type: [StorageTypes.MEMORY, [Validators.required]], - read_records_count: [100, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]], - max_records_count: [100000, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]], - data_folder_path: ['./data/', []], + read_records_count: [100, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required, Validators.pattern(/^[^.\s]+$/)]], + max_records_count: [100000, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required, Validators.pattern(/^[^.\s]+$/)]], + data_folder_path: ['./data/', [Validators.pattern(/^[^\s]+$/)]], max_file_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], max_read_records_count: [10, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], max_records_per_file: [10000, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], - data_file_path: ['./data/data.db', []], + data_file_path: ['./data/data.db', [Validators.pattern(/^[^\s]+$/)]], messages_ttl_check_in_hours: [1, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], messages_ttl_in_days: [7, [Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], @@ -147,9 +148,9 @@ export class GatewayConfigurationComponent implements OnInit { }), connectors: this.fb.array([]), logs: this.fb.group({ - dateFormat: ['%Y-%m-%d %H:%M:%S', [Validators.required]], + dateFormat: ['%Y-%m-%d %H:%M:%S', [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)]], logFormat: ['%(asctime)s - |%(levelname)s| - [%(filename)s] - %(module)s - %(funcName)s - %(lineno)d - %(message)s', - [Validators.required]], + [Validators.required, Validators.pattern(/^[^\s].*[^\s]$/)]], type: ['remote', [Validators.required]], remote: this.fb.group({ enabled: [false], @@ -204,7 +205,7 @@ export class GatewayConfigurationComponent implements OnInit { securityGroup.get('type').valueChanges.subscribe(type => { this.removeAllSecurityValidators(); if (type === SecurityTypes.ACCESS_TOKEN) { - securityGroup.get('accessToken').addValidators([Validators.required]); + securityGroup.get('accessToken').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); securityGroup.get('accessToken').updateValueAndValidity(); } else if (type === SecurityTypes.TLS_PRIVATE_KEY) { securityGroup.get('caCert').addValidators([Validators.required]); @@ -214,7 +215,7 @@ export class GatewayConfigurationComponent implements OnInit { securityGroup.get('cert').addValidators([Validators.required]); securityGroup.get('cert').updateValueAndValidity(); } else if (type === SecurityTypes.TLS_ACCESS_TOKEN) { - securityGroup.get('accessToken').addValidators([Validators.required]); + securityGroup.get('accessToken').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); securityGroup.get('accessToken').updateValueAndValidity(); securityGroup.get('caCert').addValidators([Validators.required]); securityGroup.get('caCert').updateValueAndValidity(); @@ -239,7 +240,7 @@ export class GatewayConfigurationComponent implements OnInit { storageGroup.get('read_records_count').updateValueAndValidity({emitEvent: false}); storageGroup.get('max_records_count').updateValueAndValidity({emitEvent: false}); } else if (type === StorageTypes.FILE) { - storageGroup.get('data_folder_path').addValidators([Validators.required]); + storageGroup.get('data_folder_path').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); storageGroup.get('max_file_count').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); storageGroup.get('max_read_records_count').addValidators( @@ -251,7 +252,7 @@ export class GatewayConfigurationComponent implements OnInit { storageGroup.get('max_read_records_count').updateValueAndValidity({emitEvent: false}); storageGroup.get('max_records_per_file').updateValueAndValidity({emitEvent: false}); } else if (type === StorageTypes.SQLITE) { - storageGroup.get('data_file_path').addValidators([Validators.required]); + storageGroup.get('data_file_path').addValidators([Validators.required, Validators.pattern(/^[^.\s]+$/)]); storageGroup.get('messages_ttl_check_in_hours').addValidators( [Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.required]); storageGroup.get('messages_ttl_in_days').addValidators( @@ -342,8 +343,8 @@ export class GatewayConfigurationComponent implements OnInit { this.initialCredentials = credentials; if (credentials.credentialsType === DeviceCredentialsType.ACCESS_TOKEN || security.type === SecurityTypes.TLS_ACCESS_TOKEN) { this.gatewayConfigGroup.get('thingsboard.security.type').setValue(security.type === SecurityTypes.TLS_ACCESS_TOKEN - ? SecurityTypes.TLS_ACCESS_TOKEN - : SecurityTypes.ACCESS_TOKEN); + ? SecurityTypes.TLS_ACCESS_TOKEN + : SecurityTypes.ACCESS_TOKEN); this.gatewayConfigGroup.get('thingsboard.security.accessToken').setValue(credentials.credentialsId); if(security.type === SecurityTypes.TLS_ACCESS_TOKEN) { this.gatewayConfigGroup.get('thingsboard.security.caCert').setValue(security.caCert); @@ -407,9 +408,9 @@ export class GatewayConfigurationComponent implements OnInit { addCommand(command: any = {}): void { const commandsFormArray = this.commandFormArray(); const commandFormGroup = this.fb.group({ - attributeOnGateway: [command.attributeOnGateway || null, [Validators.required]], - command: [command.command || null, [Validators.required]], - timeout: [command.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/)]], + attributeOnGateway: [command.attributeOnGateway || null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], + command: [command.command || null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], + timeout: [command.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.pattern(/^[^.\s]+$/)]], }); commandsFormArray.push(commandFormGroup); } @@ -542,7 +543,7 @@ export class GatewayConfigurationComponent implements OnInit { } saveConfig(): void { - const value = this.removeEmpty(this.gatewayConfigGroup.value); + const value = deepTrim(this.removeEmpty(this.gatewayConfigGroup.value)); value.thingsboard.statistics.commands = Object.values(value.thingsboard.statistics.commands); const attributes = []; attributes.push({ @@ -609,8 +610,8 @@ export class GatewayConfigurationComponent implements OnInit { credentialsValue.password = securityConfig.password; } newCredentials = { - credentialsType, - credentialsValue: JSON.stringify(credentialsValue) + credentialsType, + credentialsValue: JSON.stringify(credentialsValue) }; } } else if (securityConfig.type === SecurityTypes.ACCESS_TOKEN || securityConfig.type === SecurityTypes.TLS_ACCESS_TOKEN) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html index 973b3e02b7..e195dcece9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-logs.component.html @@ -25,13 +25,13 @@ matSort [matSortActive]="pageLink.sortOrder.property" [matSortDirection]="pageLink.sortDirection()" matSortDisableClear> - {{ 'widgets.gateway.created-time' | translate }} + {{ 'widgets.gateway.created-time' | translate }} {{ attribute.ts | date:'yyyy-MM-dd HH:mm:ss' }} - {{ 'widgets.gateway.status' | translate }} + {{ 'widgets.gateway.status' | translate }} {{ attribute.status }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts index 2e1deb900a..503f5643bf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-statistics.component.ts @@ -50,6 +50,7 @@ export class GatewayStatisticsComponent implements AfterViewInit { public general: boolean; public isNumericData = false; + public dataTypeDefined: boolean = false; public chartInited: boolean; private flot: TbFlot; private flotCtx: WidgetContext; @@ -155,6 +156,7 @@ export class GatewayStatisticsComponent implements AfterViewInit { subscriptionInfo[0].timeseries = [{name: attr, label: attr}]; this.subscriptionInfo = subscriptionInfo; this.changeSubscription(subscriptionInfo); + this.ctx.defaultSubscription.unsubscribe(); } private createGeneralChartsSubscription(gateway: BaseData, attrData: string[]) { @@ -175,8 +177,8 @@ export class GatewayStatisticsComponent implements AfterViewInit { subscriptionInfo[0].timeseries.push({name: dataKey.name, label: dataKey.label}); }); - this.subscriptionInfo = subscriptionInfo; this.changeSubscription(subscriptionInfo); + this.ctx.defaultSubscription.unsubscribe(); } private init = () => { @@ -252,7 +254,10 @@ export class GatewayStatisticsComponent implements AfterViewInit { return; } this.dataSource.data = this.subscription.data.length ? this.subscription.data[0].data : []; - this.isNumericData = this.dataSource.data.every(data => !isNaN(+data[1])); + if (this.dataSource.data.length && !this.dataTypeDefined) { + this.dataTypeDefined = true; + this.isNumericData = this.dataSource.data.every(data => !isNaN(+data[1])); + } } @@ -263,6 +268,7 @@ export class GatewayStatisticsComponent implements AfterViewInit { if (this.ctx.datasources[0].entity) { this.ctx.subscriptionApi.createSubscriptionFromInfo(widgetType.timeseries, subscriptionInfo, this.subscriptionOptions, false, true).subscribe(subscription => { + this.dataTypeDefined = false; this.subscription = subscription; this.isDataOnlyNumbers(); this.legendData = this.subscription.legendData; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts index 5d3ea09447..c543ee99fb 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/gateway/gateway-logs-settings.component.ts @@ -41,14 +41,14 @@ export class GatewayLogsSettingsComponent extends WidgetSettingsComponent { protected defaultSettings(): WidgetSettings { return { isConnectorLog: false, - connectorLogState: 'default' + connectorLogState: '' }; } protected onSettingsSet(settings: WidgetSettings) { this.gatewayLogSettingForm = this.fb.group({ isConnectorLog: [false, []], - connectorLogState: ['default', Validators.required] + connectorLogState: ['', Validators.required] }); } diff --git a/ui-ngx/src/app/shared/components/file-input.component.scss b/ui-ngx/src/app/shared/components/file-input.component.scss index 45ed704336..8577744995 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.scss +++ b/ui-ngx/src/app/shared/components/file-input.component.scss @@ -83,6 +83,12 @@ $previewSize: 100px !default; } } } + + .input-hint { + cursor:pointer; + transform: translate(5px,-3px); + position: absolute; + } } :host ::ng-deep { 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 7397f82993..053c1713bc 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2683,7 +2683,7 @@ "rpc-command-result": "Result", "rpc-command-edit-params": "Edit parameters", "select-connector": "Select connector", - "gateway-configuration": "Gateway Configuration", + "gateway-configuration": "General Configuration", "docker-label": "In order to run ThingsBoard IoT gateway in docker with credentials for this device you can use the following commands.", "copy-command": "Copy docker command", "create-new-gateway": "Create a new gateway", @@ -5329,8 +5329,8 @@ "events-title": "Gateway events form title", "events-filter": "Events filter", "event-key-contains": "Event key contains...", - "is-connector": "Is Connector", - "state-param-name": "State parameter connector name", + "is-connector": "Show for the connector", + "state-param-name": "Connector state parameter key", "status": "Status", "message": "Message", "created-time": "Created time" From 902a7a07b4fb758e5dd890ef774a8cbae71d467d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 12 Sep 2023 17:10:48 +0200 Subject: [PATCH 028/267] fixed alarm severity change --- .../data/alarm/AlarmModificationRequest.java | 2 + .../rule/engine/action/TbAlarmResult.java | 7 +- .../profile/TbDeviceProfileNodeTest.java | 93 ++++++++++++++++++- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmModificationRequest.java b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmModificationRequest.java index e40cb15d22..9270c2d696 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmModificationRequest.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/alarm/AlarmModificationRequest.java @@ -22,6 +22,8 @@ public interface AlarmModificationRequest { TenantId getTenantId(); + AlarmSeverity getSeverity(); + long getStartTs(); long getEndTs(); diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmResult.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmResult.java index 67384ebe23..85c3cb5a98 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmResult.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/action/TbAlarmResult.java @@ -37,6 +37,11 @@ public class TbAlarmResult { } public static TbAlarmResult fromAlarmResult(AlarmApiCallResult result) { - return new TbAlarmResult(result.isCreated(), result.isModified(), result.isSeverityChanged(), result.isCleared(), result.getAlarm()); + return new TbAlarmResult( + result.isCreated(), + result.isModified() && !result.isSeverityChanged(), + result.isSeverityChanged(), + result.isCleared(), + result.getAlarm()); } } 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 03a9c17a60..ad23b7492b 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 @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.alarm.AlarmInfo; +import org.thingsboard.server.common.data.alarm.AlarmModificationRequest; import org.thingsboard.server.common.data.alarm.AlarmSeverity; import org.thingsboard.server.common.data.device.profile.AlarmCondition; import org.thingsboard.server.common.data.device.profile.AlarmConditionFilter; @@ -219,6 +220,94 @@ public class TbDeviceProfileNodeTest { } + @Test + public void testAlarmSeverityUpdate() throws Exception { + init(); + + DeviceProfile deviceProfile = new DeviceProfile(); + DeviceProfileData deviceProfileData = new DeviceProfileData(); + + AlarmConditionFilter tempFilter = new AlarmConditionFilter(); + tempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); + tempFilter.setValueType(EntityKeyValueType.NUMERIC); + NumericFilterPredicate temperaturePredicate = new NumericFilterPredicate(); + temperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); + temperaturePredicate.setValue(new FilterPredicateValue<>(30.0)); + tempFilter.setPredicate(temperaturePredicate); + AlarmCondition alarmTempCondition = new AlarmCondition(); + alarmTempCondition.setCondition(Collections.singletonList(tempFilter)); + AlarmRule alarmTempRule = new AlarmRule(); + alarmTempRule.setCondition(alarmTempCondition); + + AlarmConditionFilter highTempFilter = new AlarmConditionFilter(); + highTempFilter.setKey(new AlarmConditionFilterKey(AlarmConditionKeyType.TIME_SERIES, "temperature")); + highTempFilter.setValueType(EntityKeyValueType.NUMERIC); + NumericFilterPredicate highTemperaturePredicate = new NumericFilterPredicate(); + highTemperaturePredicate.setOperation(NumericFilterPredicate.NumericOperation.GREATER); + highTemperaturePredicate.setValue(new FilterPredicateValue<>(50.0)); + highTempFilter.setPredicate(highTemperaturePredicate); + AlarmCondition alarmHighTempCondition = new AlarmCondition(); + alarmHighTempCondition.setCondition(Collections.singletonList(highTempFilter)); + AlarmRule alarmHighTempRule = new AlarmRule(); + alarmHighTempRule.setCondition(alarmHighTempCondition); + DeviceProfileAlarm dpa = new DeviceProfileAlarm(); + dpa.setId("highTemperatureAlarmID1"); + dpa.setAlarmType("highTemperatureAlarm1"); + + TreeMap createRules = new TreeMap<>(); + + createRules.put(AlarmSeverity.WARNING, alarmTempRule); + createRules.put(AlarmSeverity.CRITICAL, alarmHighTempRule); + + dpa.setCreateRules(createRules); + + deviceProfileData.setAlarms(Collections.singletonList(dpa)); + deviceProfile.setProfileData(deviceProfileData); + + Mockito.when(cache.get(tenantId, deviceId)).thenReturn(deviceProfile); + Mockito.when(timeseriesService.findLatest(tenantId, deviceId, Collections.singleton("temperature"))) + .thenReturn(Futures.immediateFuture(Collections.emptyList())); + Mockito.when(alarmService.findLatestActiveByOriginatorAndType(tenantId, deviceId, "highTemperatureAlarm1")).thenReturn(null); + registerCreateAlarmMock(alarmService.createAlarm(any()), true); + + TbMsg theMsg = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg); + + ObjectNode data = JacksonUtil.newObjectNode(); + data.put("temperature", 42); + TbMsg msg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, + TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + node.onMsg(ctx, msg); + verify(ctx).tellSuccess(msg); + verify(ctx).enqueueForTellNext(theMsg, "Alarm Created"); + verify(ctx, Mockito.never()).tellFailure(Mockito.any(), Mockito.any()); + + TbMsg theMsg2 = TbMsg.newMsg(TbMsgType.ALARM, deviceId, TbMsgMetaData.EMPTY, TbMsg.EMPTY_STRING); + when(ctx.newMsg(any(), any(TbMsgType.class), any(), any(), any(), Mockito.anyString())).thenReturn(theMsg2); + + AlarmInfo alarm = new AlarmInfo(new Alarm(new AlarmId(UUID.randomUUID()))); + alarm.setSeverity(AlarmSeverity.CRITICAL); + + Alarm oldAlarm = new Alarm(new AlarmId(UUID.randomUUID())); + oldAlarm.setSeverity(AlarmSeverity.WARNING); + var result = AlarmApiCallResult.builder() + .successful(true) + .created(false) + .modified(true) + .alarm(alarm) + .old(oldAlarm) + .build(); + + when(alarmService.updateAlarm(any())).thenReturn(result); + + data.put("temperature", 52); + TbMsg msg2 = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, deviceId, TbMsgMetaData.EMPTY, + TbMsgDataType.JSON, JacksonUtil.toString(data), null, null); + node.onMsg(ctx, msg2); + verify(ctx).tellSuccess(msg2); + verify(ctx).enqueueForTellNext(theMsg2, "Alarm Severity Updated"); + } + @Test public void testConstantKeyFilterSimple() throws Exception { init(); @@ -1605,9 +1694,9 @@ public class TbDeviceProfileNodeTest { private void registerCreateAlarmMock(AlarmApiCallResult a, boolean created) { when(a).thenAnswer(invocationOnMock -> { -// AlarmCreateOrUpdateActiveRequest request = invocationOnMock.getArgument(0); AlarmInfo alarm = new AlarmInfo(new Alarm(new AlarmId(UUID.randomUUID()))); - alarm.setSeverity(AlarmSeverity.CRITICAL); + AlarmModificationRequest request = invocationOnMock.getArgument(0); + alarm.setSeverity(request.getSeverity()); return AlarmApiCallResult.builder() .successful(true) .created(created) From 65145284ca6c64091a2754bad081af11c9c5ed18 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 12 Sep 2023 19:08:40 +0300 Subject: [PATCH 029/267] UI: Improved view gateway dashboard and updated gateway widget types --- .../json/demo/dashboards/gateway_list.json | 656 ++++++------------ .../widget_types/gateway_configuration2.json | 6 +- .../widget_types/gateway_connector.json | 10 +- .../gateway_general_statistics.json | 8 +- .../system/widget_types/gateway_logs.json | 10 +- .../widget_types/gateway_statistics.json | 10 +- .../json/system/widget_types/service_rpc.json | 6 +- .../widget/dialog/custom-dialog.service.ts | 14 +- .../device-gateway-command.component.html | 5 +- .../device-gateway-command.component.scss | 32 + .../gateway-configuration.component.html | 13 +- .../gateway-configuration.component.scss | 21 +- .../gateway/gateway-connectors.component.html | 250 +++---- .../gateway/gateway-connectors.component.scss | 16 +- 14 files changed, 452 insertions(+), 605 deletions(-) diff --git a/application/src/main/data/json/demo/dashboards/gateway_list.json b/application/src/main/data/json/demo/dashboards/gateway_list.json index 7abee6cbe4..643672e954 100644 --- a/application/src/main/data/json/demo/dashboards/gateway_list.json +++ b/application/src/main/data/json/demo/dashboards/gateway_list.json @@ -7,13 +7,7 @@ "description": "", "widgets": { "23b9adc5-b3bd-040f-e5eb-a45925c73257": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -82,15 +76,33 @@ "type": "entityField", "label": "Created time", "color": "#2196f3", - "settings": {}, - "_hash": 0.4570900758216545 + "settings": { + "columnWidth": "140px", + "useCellStyleFunction": false, + "useCellContentFunction": false, + "defaultColumnVisibility": "visible", + "columnSelectionToDisplay": "enabled" + }, + "_hash": 0.4570900758216545, + "aggregationType": null, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null }, { "name": "name", "type": "entityField", "label": "Gateway name", "color": "#4caf50", - "settings": {}, + "settings": { + "columnWidth": "20%", + "useCellStyleFunction": false, + "useCellContentFunction": false, + "defaultColumnVisibility": "visible", + "columnSelectionToDisplay": "enabled" + }, "_hash": 0.45934623767875316, "aggregationType": null, "units": null, @@ -105,7 +117,7 @@ "label": "Status", "color": "#f44336", "settings": { - "columnWidth": "0px", + "columnWidth": "20%", "useCellStyleFunction": false, "useCellContentFunction": true, "cellContentFunction": "var newValue = value == 'true' ? \"Active\" : \"Inactive\";\r\nvar bgColor = value == 'true' ? 'rgba(25,128,56, .06)': 'rgba(203,37,48, .06)',\r\ncolor = value == 'true' ? 'rgb(25,128,56)': 'rgb(203,37,48)';\r\nreturn `
${newValue}
`", @@ -126,7 +138,7 @@ "label": "Active Connectors", "color": "#3f51b5", "settings": { - "columnWidth": "0px", + "columnWidth": "20%", "useCellStyleFunction": false, "useCellContentFunction": true, "cellContentFunction": "return value?JSON.parse(value).length:0;", @@ -146,8 +158,20 @@ "type": "attribute", "label": "Version", "color": "#8bc34a", - "settings": {}, - "_hash": 0.4705163811361781 + "settings": { + "columnWidth": "40%", + "useCellStyleFunction": false, + "useCellContentFunction": false, + "defaultColumnVisibility": "visible", + "columnSelectionToDisplay": "enabled" + }, + "_hash": 0.4705163811361781, + "aggregationType": null, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null } ] } @@ -168,7 +192,7 @@ "dialogTitle": "Docker commands", "dialogHideDashboardToolbar": true, "dialogWidth": null, - "dialogHeight": 45, + "dialogHeight": 55, "openInSeparateDialog": true, "openInPopover": false, "id": "ae2e5995-505f-a241-5fb2-6cbaf08b1b55" @@ -178,18 +202,14 @@ "icon": "settings", "useShowWidgetActionFunction": null, "showWidgetActionFunction": "return true;", - "type": "openDashboardState", - "targetDashboardStateId": "configuration", - "setEntityId": true, - "stateEntityParamName": null, - "openRightLayout": false, - "dialogTitle": "Gateway configuration", - "dialogHideDashboardToolbar": true, - "dialogWidth": null, - "dialogHeight": null, - "openInSeparateDialog": true, + "type": "customPretty", + "customHtml": "\n

gateway.gateway-configuration

\n \n \n
\n\n\n
\n\n", + "customCss": ".gateway-config {\n width: 800px !important;\n padding: 0 !important;\n min-height: 75vh;\n max-width: 100%;\n display: grid !important;\n}\n\n@media screen and (max-width: 599px) {\n .mat-mdc-dialog-content {\n max-height: calc(100% - 60px) !important;\n }\n}", + "customFunction": "let $injector = widgetContext.$scope.$injector;\nlet customDialog = $injector.get(widgetContext.servicesMap.get('customDialog'));\n\nopenAddEntityDialog();\n\nfunction openAddEntityDialog() {\n customDialog.customDialog(htmlTemplate, AddEntityDialogController).subscribe();\n}\n\nfunction AddEntityDialogController(instance) {\n let vm = instance;\n \n vm.device = additionalParams.entity.id;\n\n vm.cancel = function() {\n vm.dialogRef.close(null);\n };\n}\n", + "customResources": [], + "openInSeparateDialog": false, "openInPopover": false, - "id": "c0c8eb55-48c6-8a4e-ad9a-427507e86916" + "id": "a54acd30-5c5f-d709-b892-5fc14f780e34" }, { "name": "Connectors", @@ -245,20 +265,21 @@ "widgetStyle": {}, "widgetCss": "", "pageSize": 1024, - "noDataDisplayMessage": "" + "noDataDisplayMessage": "", + "configMode": "advanced", + "titleFont": null, + "titleColor": null, + "titleIcon": null, + "iconColor": null, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "23b9adc5-b3bd-040f-e5eb-a45925c73257" + "id": "23b9adc5-b3bd-040f-e5eb-a45925c73257", + "typeFullFqn": "system.cards.entities_table" }, "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_configuration2", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 6, "config": { @@ -298,7 +319,7 @@ "showTitle": false, "backgroundColor": "#fff", "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", + "padding": "0px", "settings": {}, "title": "New Gateway configuration", "showTitleIcon": false, @@ -315,20 +336,16 @@ "pageSize": 1024, "noDataDisplayMessage": "", "showLegend": false, - "useDashboardTimewindow": true + "useDashboardTimewindow": true, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99" + "id": "d4a1ffc4-c9f6-7b15-bca0-17feb58bac99", + "typeFullFqn": "system.gateway_widgets.gateway_configuration2" }, "02a05113-d878-b086-328e-75bd6f02b2bb": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_connector", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 11, "sizeY": 8, "config": { @@ -375,14 +392,14 @@ } }, "showTitle": false, - "backgroundColor": "#fff", + "backgroundColor": "#FFFFFF01", "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", + "padding": "0px", "settings": {}, "title": "New Gateway connector", "showTitleIcon": false, "titleTooltip": "", - "dropShadow": true, + "dropShadow": false, "enableFullscreen": false, "enableDataExport": false, "widgetStyle": {}, @@ -398,16 +415,11 @@ }, "row": 0, "col": 0, - "id": "02a05113-d878-b086-328e-75bd6f02b2bb" + "id": "02a05113-d878-b086-328e-75bd6f02b2bb", + "typeFullFqn": "system.gateway_widgets.gateway_connector" }, "79f59106-758f-c428-8b93-4341faea705d": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -569,9 +581,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -583,20 +593,16 @@ "pageSize": 1024, "noDataDisplayMessage": "", "enableDataExport": false, - "displayTimewindow": true + "displayTimewindow": true, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "79f59106-758f-c428-8b93-4341faea705d" + "id": "79f59106-758f-c428-8b93-4341faea705d", + "typeFullFqn": "system.cards.markdown_card" }, "60dcf518-8fc3-3539-8ff8-ce94bda39f3a": { - "isSystemType": true, - "bundleAlias": "alarm_widgets", - "typeAlias": "alarms_table", "type": "alarm", - "title": "New widget", - "image": null, - "description": null, "sizeX": 10.5, "sizeY": 6.5, "config": { @@ -718,9 +724,7 @@ "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", "titleTooltip": "", - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "displayTimewindow": false, "actions": {}, "datasources": [], @@ -733,20 +737,16 @@ "typeList": [], "searchPropagatedAlarms": false }, - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "60dcf518-8fc3-3539-8ff8-ce94bda39f3a" + "id": "60dcf518-8fc3-3539-8ff8-ce94bda39f3a", + "typeFullFqn": "system.alarm_widgets.alarms_table" }, "27e6b37c-085e-824d-fb13-69651a545ec1": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_logs", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 3, "config": { @@ -786,11 +786,9 @@ "settings": {}, "title": "Gateway Logs", "showTitleIcon": false, - "dropShadow": false, + "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "border-radius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", @@ -802,20 +800,16 @@ "titleStyle": { "fontSize": "16px", "fontWeight": 400 - } + }, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "27e6b37c-085e-824d-fb13-69651a545ec1" + "id": "27e6b37c-085e-824d-fb13-69651a545ec1", + "typeFullFqn": "system.gateway_widgets.gateway_logs" }, "bcd04dbf-c82a-ca13-6e88-a74f32b4348a": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_logs", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 3, "config": { @@ -858,11 +852,9 @@ }, "title": "Gateway Logs", "showTitleIcon": false, - "dropShadow": false, + "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "border-radius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", @@ -874,20 +866,16 @@ "titleStyle": { "fontSize": "16px", "fontWeight": 400 - } + }, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "bcd04dbf-c82a-ca13-6e88-a74f32b4348a" + "id": "bcd04dbf-c82a-ca13-6e88-a74f32b4348a", + "typeFullFqn": "system.gateway_widgets.gateway_logs" }, "9b88dc51-b186-90ef-5afb-9648e6e2ac9a": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_statistics", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 5, "config": { @@ -984,9 +972,7 @@ "displayTimewindow": false, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "border-radius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", @@ -1001,20 +987,16 @@ "showAvg": true, "showTotal": false, "showLatest": false - } + }, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "9b88dc51-b186-90ef-5afb-9648e6e2ac9a" + "id": "9b88dc51-b186-90ef-5afb-9648e6e2ac9a", + "typeFullFqn": "system.gateway_widgets.gateway_statistics" }, "2a318e56-5c83-4f82-bf23-df72dd7e3edf": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_remote_shell", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1083,16 +1065,11 @@ }, "row": 0, "col": 0, - "id": "2a318e56-5c83-4f82-bf23-df72dd7e3edf" + "id": "2a318e56-5c83-4f82-bf23-df72dd7e3edf", + "typeFullFqn": "system.control_widgets.rpc_remote_shell" }, "c50e294a-265a-d13c-c772-b56c4df953fe": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "gateway_general_statistics", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 5, "config": { @@ -1283,9 +1260,7 @@ "displayTimewindow": false, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "border-radius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", @@ -1300,20 +1275,16 @@ "showAvg": false, "showTotal": false, "showLatest": false - } + }, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "c50e294a-265a-d13c-c772-b56c4df953fe" + "id": "c50e294a-265a-d13c-c772-b56c4df953fe", + "typeFullFqn": "system.gateway_widgets.gateway_general_statistics" }, "da01e13f-c108-39fd-2a74-b40da088769a": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "timeseries_table", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 6.5, "config": { @@ -1417,32 +1388,26 @@ }, "useDashboardTimewindow": false, "showLegend": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "actions": {}, "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", "displayTimewindow": true, "titleTooltip": "", - "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-debug {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-warning {\r\n color: orange;\r\n background: rgba(255, 165, 0, 0.1);\r\n }\r\n\r\n .status-error {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n\r\n .status-info {\r\n color: blue;\r\n background: rgba(0, 0, 128, 0.1);\r\n }\r\n \r\n .msg-status-exception {\r\n color: red;\r\n }", + "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n}\r\n\r\n.status-debug {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n}\r\n\r\n.status-warning {\r\n color: orange;\r\n background: rgba(255, 165, 0, 0.1);\r\n}\r\n\r\n.status-error {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n}\r\n\r\n.status-info {\r\n color: blue;\r\n background: rgba(0, 0, 128, 0.1);\r\n}\r\n\r\n.msg-status-exception {\r\n color: red;\r\n}", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "da01e13f-c108-39fd-2a74-b40da088769a" + "id": "da01e13f-c108-39fd-2a74-b40da088769a", + "typeFullFqn": "system.cards.timeseries_table" }, "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_debug_terminal", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1490,9 +1455,7 @@ "title": "New RPC debug terminal", "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -1508,20 +1471,16 @@ "titleTooltip": "", "widgetCss": "", "pageSize": 1024, - "noDataDisplayMessage": "" + "noDataDisplayMessage": "", + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f" + "id": "ce3065bf-d898-2c03-6236-ce1b6cdf1f3f", + "typeFullFqn": "system.control_widgets.rpc_debug_terminal" }, "46b68eb5-7e2d-bca1-c2ef-061b64575218": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "service_rpc", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 4, "sizeY": 2, "config": { @@ -1575,9 +1534,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "titleStyle": { "fontSize": "16px", @@ -1586,20 +1543,16 @@ "pageSize": 1024, "noDataDisplayMessage": "", "enableDataExport": false, - "showLegend": false + "showLegend": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "46b68eb5-7e2d-bca1-c2ef-061b64575218" + "id": "46b68eb5-7e2d-bca1-c2ef-061b64575218", + "typeFullFqn": "system.gateway_widgets.service_rpc" }, "878c68fd-71cb-21d4-684a-b5b5a4526b43": { - "isSystemType": true, - "bundleAlias": "gateway_widgets", - "typeAlias": "service_rpc", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 4, "sizeY": 2, "config": { @@ -1620,9 +1573,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "widgetCss": "", "titleStyle": { "fontSize": "16px", @@ -1631,20 +1582,16 @@ "pageSize": 1024, "noDataDisplayMessage": "", "enableDataExport": false, - "showLegend": false + "showLegend": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "878c68fd-71cb-21d4-684a-b5b5a4526b43" + "id": "878c68fd-71cb-21d4-684a-b5b5a4526b43", + "typeFullFqn": "system.gateway_widgets.service_rpc" }, "0fc7dcf3-32a2-0159-738e-96956bf0d450": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "timeseries_table", "type": "timeseries", - "title": "New widget", - "image": null, - "description": null, "sizeX": 8, "sizeY": 6.5, "config": { @@ -1749,32 +1696,26 @@ }, "useDashboardTimewindow": false, "showLegend": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "actions": {}, "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", "displayTimewindow": true, "titleTooltip": "", - "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-debug {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-warning {\r\n color: orange;\r\n background: rgba(255, 165, 0, 0.1);\r\n }\r\n\r\n .status-error {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n\r\n .status-info {\r\n color: blue;\r\n background: rgba(0, 0, 128, 0.1);\r\n }\r\n \r\n .msg-status-exception {\r\n color: red;\r\n }", + "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n}\r\n\r\n.status-debug {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n}\r\n\r\n.status-warning {\r\n color: orange;\r\n background: rgba(255, 165, 0, 0.1);\r\n}\r\n\r\n.status-error {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n}\r\n\r\n.status-info {\r\n color: blue;\r\n background: rgba(0, 0, 128, 0.1);\r\n}\r\n\r\n.msg-status-exception {\r\n color: red;\r\n}", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "0fc7dcf3-32a2-0159-738e-96956bf0d450" + "id": "0fc7dcf3-32a2-0159-738e-96956bf0d450", + "typeFullFqn": "system.cards.timeseries_table" }, "6e136fbc-545b-4926-c0a9-79348f35628a": { - "isSystemType": true, - "bundleAlias": "control_widgets", - "typeAlias": "rpc_debug_terminal", "type": "rpc", - "title": "New widget", - "image": null, - "description": null, "sizeX": 9.5, "sizeY": 5.5, "config": { @@ -1822,9 +1763,7 @@ "title": "New RPC debug terminal", "dropShadow": true, "enableFullscreen": true, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -1840,20 +1779,16 @@ "titleTooltip": "", "widgetCss": "", "pageSize": 1024, - "noDataDisplayMessage": "" + "noDataDisplayMessage": "", + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "6e136fbc-545b-4926-c0a9-79348f35628a" + "id": "6e136fbc-545b-4926-c0a9-79348f35628a", + "typeFullFqn": "system.control_widgets.rpc_debug_terminal" }, "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -1896,7 +1831,7 @@ "padding": "8px", "settings": { "useMarkdownTextFunction": false, - "markdownTextPattern": "
\r\n\r\n
", + "markdownTextPattern": "
\r\n \r\n
", "applyDefaultMarkdownStyle": false, "markdownCss": ".action-buttons-container {\r\n display: flex;\r\n flex-wrap: wrap;\r\n flex-direction: row;\r\n height: 100%;\r\n width: 100%;\r\n align-content: center;\r\n}\r\n\r\nbutton {\r\n flex-grow: 1;\r\n margin: 10px;\r\n min-width: 150px;\r\n height: auto;\r\n}" }, @@ -1907,9 +1842,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -1931,7 +1864,7 @@ "dialogTitle": "Launch command", "dialogHideDashboardToolbar": true, "dialogWidth": null, - "dialogHeight": 45, + "dialogHeight": 55, "openInSeparateDialog": true, "openInPopover": false, "id": "337c767b-3217-d3d3-b955-7b0bd0858a1d" @@ -1941,20 +1874,16 @@ "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19" + "id": "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19", + "typeFullFqn": "system.cards.markdown_card" }, "61d149e8-b249-5526-e5d7-6ad58413982e": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -2025,9 +1954,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -2125,20 +2052,16 @@ "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "61d149e8-b249-5526-e5d7-6ad58413982e" + "id": "61d149e8-b249-5526-e5d7-6ad58413982e", + "typeFullFqn": "system.cards.markdown_card" }, "3d661190-7463-ba61-6793-503c85af67ec": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -2196,9 +2119,7 @@ "titleTooltip": "", "dropShadow": true, "enableFullscreen": false, - "widgetStyle": { - "borderRadius": "10px" - }, + "widgetStyle": {}, "titleStyle": { "fontSize": "16px", "fontWeight": 400 @@ -2209,20 +2130,16 @@ "widgetCss": "", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "3d661190-7463-ba61-6793-503c85af67ec" + "id": "3d661190-7463-ba61-6793-503c85af67ec", + "typeFullFqn": "system.cards.markdown_card" }, "1615bd4e-c0a4-c32c-3706-3c83214cb8d7": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2361,26 +2278,20 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "" }, "row": 0, "col": 0, - "id": "1615bd4e-c0a4-c32c-3706-3c83214cb8d7" + "id": "1615bd4e-c0a4-c32c-3706-3c83214cb8d7", + "typeFullFqn": "system.cards.entities_table" }, "aafba3d8-a381-21c0-ecbe-446da3cdc041": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2519,26 +2430,20 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", - "enableDataExport": false + "enableDataExport": false, + "borderRadius": "4px" }, "row": 0, "col": 0, - "id": "aafba3d8-a381-21c0-ecbe-446da3cdc041" + "id": "aafba3d8-a381-21c0-ecbe-446da3cdc041", + "typeFullFqn": "system.cards.entities_table" }, "7f676bb2-bde2-10e7-80d8-25dd734e8e22": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2677,9 +2582,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -2687,16 +2590,11 @@ }, "row": 0, "col": 0, - "id": "7f676bb2-bde2-10e7-80d8-25dd734e8e22" + "id": "7f676bb2-bde2-10e7-80d8-25dd734e8e22", + "typeFullFqn": "system.cards.entities_table" }, "d64482d8-001a-6f33-9b56-665530098fe5": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2835,9 +2733,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -2845,16 +2741,11 @@ }, "row": 0, "col": 0, - "id": "d64482d8-001a-6f33-9b56-665530098fe5" + "id": "d64482d8-001a-6f33-9b56-665530098fe5", + "typeFullFqn": "system.cards.entities_table" }, "bb27723a-989c-2327-5808-b56d490b93ab": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -2993,9 +2884,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3003,16 +2892,11 @@ }, "row": 0, "col": 0, - "id": "bb27723a-989c-2327-5808-b56d490b93ab" + "id": "bb27723a-989c-2327-5808-b56d490b93ab", + "typeFullFqn": "system.cards.entities_table" }, "e3a9539d-2ccb-96e0-2afa-36f93e40233d": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3151,9 +3035,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3161,16 +3043,11 @@ }, "row": 0, "col": 0, - "id": "e3a9539d-2ccb-96e0-2afa-36f93e40233d" + "id": "e3a9539d-2ccb-96e0-2afa-36f93e40233d", + "typeFullFqn": "system.cards.entities_table" }, "cf2eba6b-44f6-9cc2-6089-35c735f54898": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3309,9 +3186,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3319,16 +3194,11 @@ }, "row": 0, "col": 0, - "id": "cf2eba6b-44f6-9cc2-6089-35c735f54898" + "id": "cf2eba6b-44f6-9cc2-6089-35c735f54898", + "typeFullFqn": "system.cards.entities_table" }, "3f6ed61b-f5af-13e3-7505-f69fd53f8211": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3467,9 +3337,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3477,16 +3345,11 @@ }, "row": 0, "col": 0, - "id": "3f6ed61b-f5af-13e3-7505-f69fd53f8211" + "id": "3f6ed61b-f5af-13e3-7505-f69fd53f8211", + "typeFullFqn": "system.cards.entities_table" }, "b06cecaa-2806-65a9-782d-4f2d8cf95a6c": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3625,9 +3488,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3635,16 +3496,11 @@ }, "row": 0, "col": 0, - "id": "b06cecaa-2806-65a9-782d-4f2d8cf95a6c" + "id": "b06cecaa-2806-65a9-782d-4f2d8cf95a6c", + "typeFullFqn": "system.cards.entities_table" }, "c3d39b60-a668-7f5e-e6f4-cae27151f4aa": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3783,9 +3639,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3793,16 +3647,11 @@ }, "row": 0, "col": 0, - "id": "c3d39b60-a668-7f5e-e6f4-cae27151f4aa" + "id": "c3d39b60-a668-7f5e-e6f4-cae27151f4aa", + "typeFullFqn": "system.cards.entities_table" }, "f78a0d66-60cb-188f-857f-9acd4d24bd5a": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -3941,9 +3790,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -3951,16 +3798,11 @@ }, "row": 0, "col": 0, - "id": "f78a0d66-60cb-188f-857f-9acd4d24bd5a" + "id": "f78a0d66-60cb-188f-857f-9acd4d24bd5a", + "typeFullFqn": "system.cards.entities_table" }, "b81a171c-77c0-b857-21d2-cff02a1cb733": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4099,9 +3941,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4109,16 +3949,11 @@ }, "row": 0, "col": 0, - "id": "b81a171c-77c0-b857-21d2-cff02a1cb733" + "id": "b81a171c-77c0-b857-21d2-cff02a1cb733", + "typeFullFqn": "system.cards.entities_table" }, "0e399bef-01d2-4e4e-02d2-e254ebe91e56": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4257,9 +4092,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4267,16 +4100,11 @@ }, "row": 0, "col": 0, - "id": "0e399bef-01d2-4e4e-02d2-e254ebe91e56" + "id": "0e399bef-01d2-4e4e-02d2-e254ebe91e56", + "typeFullFqn": "system.cards.entities_table" }, "819c1d39-de7c-8ac3-858e-0040d286823e": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4415,9 +4243,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4425,16 +4251,11 @@ }, "row": 0, "col": 0, - "id": "819c1d39-de7c-8ac3-858e-0040d286823e" + "id": "819c1d39-de7c-8ac3-858e-0040d286823e", + "typeFullFqn": "system.cards.entities_table" }, "d4f73f32-f719-98bb-d427-b5c8957e8f47": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4573,9 +4394,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4583,16 +4402,11 @@ }, "row": 0, "col": 0, - "id": "d4f73f32-f719-98bb-d427-b5c8957e8f47" + "id": "d4f73f32-f719-98bb-d427-b5c8957e8f47", + "typeFullFqn": "system.cards.entities_table" }, "f16a258c-3f6c-9317-fda7-48b33d8fe8b9": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4731,9 +4545,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4741,16 +4553,11 @@ }, "row": 0, "col": 0, - "id": "f16a258c-3f6c-9317-fda7-48b33d8fe8b9" + "id": "f16a258c-3f6c-9317-fda7-48b33d8fe8b9", + "typeFullFqn": "system.cards.entities_table" }, "d1951ec7-ab13-87e4-bc05-ce2318dca353": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -4889,9 +4696,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -4899,16 +4704,11 @@ }, "row": 0, "col": 0, - "id": "d1951ec7-ab13-87e4-bc05-ce2318dca353" + "id": "d1951ec7-ab13-87e4-bc05-ce2318dca353", + "typeFullFqn": "system.cards.entities_table" }, "75b6372d-4def-42b4-8774-4edf413a8b83": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "entities_table", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 7.5, "sizeY": 6.5, "config": { @@ -5047,9 +4847,7 @@ "displayTimewindow": true, "showTitleIcon": false, "titleTooltip": "", - "widgetStyle": { - "borderRadius": " 0 0 10px 10px" - }, + "widgetStyle": {}, "widgetCss": ".status {\r\n border-radius: 20px;\r\n font-weight: 500;\r\n padding: 5px 15px;\r\n }\r\n\r\n .status-active {\r\n color: green;\r\n background: rgba(0, 128, 0, 0.1);\r\n }\r\n\r\n .status-inactive {\r\n color: red;\r\n background: rgba(255, 0, 0, 0.1);\r\n }\r\n", "pageSize": 1024, "noDataDisplayMessage": "", @@ -5057,16 +4855,11 @@ }, "row": 0, "col": 0, - "id": "75b6372d-4def-42b4-8774-4edf413a8b83" + "id": "75b6372d-4def-42b4-8774-4edf413a8b83", + "typeFullFqn": "system.cards.entities_table" }, "dfda1a57-6c04-3482-2054-84954bbef626": { - "isSystemType": true, - "bundleAlias": "cards", - "typeAlias": "markdown_card", "type": "latest", - "title": "New widget", - "image": null, - "description": null, "sizeX": 5, "sizeY": 3.5, "config": { @@ -5106,7 +4899,7 @@ "showTitle": false, "backgroundColor": "#fff", "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", + "padding": "0px", "settings": { "useMarkdownTextFunction": true, "markdownTextFunction": "return `
\n\n
`;", @@ -5152,7 +4945,8 @@ }, "row": 0, "col": 0, - "id": "dfda1a57-6c04-3482-2054-84954bbef626" + "id": "dfda1a57-6c04-3482-2054-84954bbef626", + "typeFullFqn": "system.cards.markdown_card" } }, "states": { @@ -5172,11 +4966,11 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 48, - "margin": 5, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, - "mobileAutoFillHeight": false, + "mobileAutoFillHeight": true, "mobileRowHeight": 70, "outerMargin": true } @@ -5200,7 +4994,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 24, - "margin": 0, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5227,7 +5021,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 24, - "margin": 10, + "margin": 0, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5245,7 +5039,7 @@ "main": { "widgets": { "79f59106-758f-c428-8b93-4341faea705d": { - "sizeX": 41, + "sizeX": 40, "sizeY": 3, "row": 0, "col": 0, @@ -5253,29 +5047,29 @@ "mobileOrder": 2 }, "60dcf518-8fc3-3539-8ff8-ce94bda39f3a": { - "sizeX": 41, + "sizeX": 40, "sizeY": 10, "row": 12, "col": 0 }, "fb9df382-6ef3-4aa6-bc13-8bf8e300ba19": { - "sizeX": 7, + "sizeX": 8, "sizeY": 3, "row": 0, - "col": 41, + "col": 40, "mobileOrder": 0, "mobileHeight": 1 }, "61d149e8-b249-5526-e5d7-6ad58413982e": { - "sizeX": 7, + "sizeX": 8, "sizeY": 19, "row": 3, - "col": 41, + "col": 40, "mobileOrder": 1, "mobileHeight": 3 }, "3d661190-7463-ba61-6793-503c85af67ec": { - "sizeX": 41, + "sizeX": 40, "sizeY": 9, "row": 3, "col": 0 @@ -5311,7 +5105,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 48, - "margin": 10, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5338,7 +5132,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 24, - "margin": 10, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5372,7 +5166,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 48, - "margin": 5, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5442,7 +5236,7 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 45, - "margin": 5, + "margin": 12, "backgroundSizeMode": "100%", "autoFillHeight": true, "backgroundImageUrl": null, @@ -5486,9 +5280,9 @@ "gridSettings": { "backgroundColor": "#eeeeee", "columns": 48, - "margin": 5, + "margin": 12, "backgroundSizeMode": "100%", - "autoFillHeight": false, + "autoFillHeight": true, "backgroundImageUrl": null, "mobileAutoFillHeight": false, "mobileRowHeight": 70, diff --git a/application/src/main/data/json/system/widget_types/gateway_configuration2.json b/application/src/main/data/json/system/widget_types/gateway_configuration2.json index 45eb8f10ad..7f90ea47cd 100644 --- a/application/src/main/data/json/system/widget_types/gateway_configuration2.json +++ b/application/src/main/data/json/system/widget_types/gateway_configuration2.json @@ -1,8 +1,8 @@ { "fqn": "gateway_widgets.gateway_configuration2", - "name": "Gateway configuration (New)", + "name": "Gateway general configuration", "deprecated": false, - "image": "data:image/jpeg;base64,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ii3bMj5ytRKUXRfXI+nX7lP95c2MS6LR7nIvE14C9kW6GU4nLsXkYCIm5VnZTleH1fVnWyF/wX95ejZo6ShCqymG/tu8Elrxk1meelEtkETXy0kFCPJR7A2kGdGclcdgy1UpJ+5Qj2Tt8dxWPimMdaz1OQgGDgn7u6M7W56sYqWBxeHmuuY9s3ibzTRlJCXt9vfTRgsrPMoG5qCPa1Ys0Wtf78EanZWpf77hs3eInbO2sdGsG1WbBGGhm7ZVk2M1afGWc0ThYVu3XZNncbGv8c71GPYN6t6tv3kladrTLrNl3FvQLvBM6vKyFbsWT6Hta312UYwfUpSlOn7xZFFwkdBdrFxbBudowVg4RVq3ZK4jb46LkGhojJM9DmzaO51KVdHjYxR8nJqfvHTRo+bqNXxIqLSZ0j0lGjNdX46ySKaCREUDxMSd6WTP+8ctmrxBRq8TjItBiaNQXhYRcqBVTx7A6rVYy8NDOmabBwvHx61WlVlIyMVarMVFomKcsyRzhJFJBIiKH7xCLimjld2zUiopVRwserZp8RwqVGGhm7ZVk2/YQRqdlal/9Tp19m4I1OytSgyhymqUZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScGdH6V6eLj+PHx/Hj4/jx8fx4+P48fH8ePj+PHx/Hj4/jx8fx4+P48fH8ePj+PHx/Hj4/jx8fx4+P48fH8ePj+PHx/Hj4/jx8fx4+P48fH8ePj+PHx/Hj4/jx8fx4+P48fH8ePj+PHx/FsKXkVitufxzeHpSjg9KdBknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScZJxknGScJnMf7x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am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq5xJ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AXzHXy1t/wDd1/s/vv8A1rb/AO7r/Z/ff+tbf/d15AX3/rW3/wB3XkDfP+vbP/d15A3z96vWzG6VUVmysEqaT/LjJloPSgAgq2JL7yqSJ1U2otCqkqqqkZmS5IzJdZGS61Vdar5tS9GKwqdFNb0prelNb0prelNb0prelNb0prelNb0prelYSv4r5ualRf2dNDvSmt6U1vSmt6U1vSmt6U1vSmt6U1vSmt6VhOvzpWCToprelNb0prelNb0prelNb0prelNb0prelNb0prelNb0prelBjHSq0uVTo8+r99N/Cmt6U1vSmt6U1vSmt6U1vSmt6UO9KVETp8+pejFYVOimt6U1vSmt6U1vSmt6U1vSmt6U1vSmt6UO9KVETp/xb0o5+KepzqTv1S8/W5+dfvI6Uc/FPU51J36pefrc/Ov3kdKOfinqc6k79UvP1ufnXz6sU5upzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3JwpzcnCnNycKc3Uuscfxz5lxqzTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFObk4U5uThTm5OFOb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qb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41frdtTfGr9btqb41LZkNo4oKbLguIioiZTI5wuvzXaGw+GjpNuvgBjkUVMiq9VX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NX63bU3xq/W7am+NT48lG9DT5B0HNHSzjOiq4zjzXOJHcVtDQHngAsKqpnBLzaqv1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV+t21N8av1u2pvjV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", + "image": "data:image/png;base64,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", "description": "Allows to create or edit gateway configuration.", "descriptor": { "type": "latest", @@ -16,4 +16,4 @@ "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\":\"8px\",\"settings\":{},\"title\":\"Gateway configuration\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":500},\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showLegend\":false}" } -} \ No newline at end of file +} diff --git a/application/src/main/data/json/system/widget_types/gateway_connector.json b/application/src/main/data/json/system/widget_types/gateway_connector.json index 00084dde76..35549ed8bb 100644 --- a/application/src/main/data/json/system/widget_types/gateway_connector.json +++ b/application/src/main/data/json/system/widget_types/gateway_connector.json @@ -1,9 +1,9 @@ { "fqn": "gateway_widgets.gateway_connector", - "name": "Gateway connector", + "name": "Gateway connectors", "deprecated": false, - "image": "data:image/jpeg;base64,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iikAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/AK4J/wChPV6qP/MxN/1wT/0J6vUAFFFFAEN9/wAer/SmaN/yB7X/AK4p/wCgin33/Hq/0pmjf8ge1/64p/6CKALNFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/mYm/64J/6E9Xqo/8AMxN/1wT/ANCer1ABRRRQBDff8er/AEpmjf8AIHtf+uKf+gin33/Hq/0qPRW3aPa4/wCeSj9BQBaooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArw7/gpb8YfEf7P/7Avxa8beEdR/snxN4Z8N3V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j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16b5a+lHlr6UAeZf8AC2vH3/RO7T/woB/8j0f8La8ff9E7tP8AwoB/8j16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7+3SvePC/wDyD3/66H+QoA0qKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/AMzE3/XBP/Qnq9VH/mYm/wCuCf8AoT1eoAKKKKAIb7/j1f6UzRv+QPa/9cU/9BFPvv8Aj1f6UzRv+QPa/wDXFP8A0EUAWaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigClrtib2y+X78fzD39a5yuwrK1fQPPZpYfvHll9fpQB8faT/wS603w9rVxeab8RPHOmrdXZvJYLS4WGN3LZ5CgZ9Oe1e8fGn4Vf8Lj+G934d/trVtB+1GM/btOk8u4j2MG+VvfGD7Guwmge3fa6srehFNoA8E/Z+/YL034C/Ft/GS+LPEviLVJLN7JjqbrJlG28lsbuNoA5r6Z8L/8g9/+uh/kKx7WwmvWxGjN79h+NdDpVh/Z1r5e7czHcT70AWaKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/zMTf9cE/9Cer1Uf8AmYm/64J/6E9XqACiiigCG+/49X+lM0b/AJA9r/1xT/0EU++/49X+lM0b/kD2v/XFP/QRQBZooooAK5P44Xs9h8Nb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f7GvP+fW5/79N/hR/Y15/wA+tz/36b/CgCtRVn+xrz/n1uf+/Tf4Uf2Nef8APrc/9+m/woArUVZ/sa8/59bn/v03+FH9jXn/AD63P/fpv8KAK1FWf7GvP+fW5/79N/hR/Y15/wA+tz/36b/CgCtRVn+xrz/n1uf+/Tf4Uf2Nef8APrc/9+m/woArUVZ/sa8/59bn/v03+FH9jXn/AD63P/fpv8KAK1FWf7GvP+fW5/79N/hR/Y15/wA+tz/36b/CgCtRVn+xrz/n1uf+/Tf4Uf2Nef8APrc/9+m/woArV1vgP/kDyf8AXY/+grXN/wBjXn/Prc/9+m/wrp/BVtJa6VIssckbGUnDqVOMCgDYooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP/MxN/wBcE/8AQnq9VH/mYm/64J/6E9XqACiiigCG+/49X+lM0b/kD2v/AFxT/wBBFPvv+PV/pTNG/wCQPa/9cU/9BFAFmiiigArmPi//AMiT/wBxCw/9LIa6euY+L/8AyJP/AHELD/0shoAyqKKKACiiigAooooAKv8Ahn/kOQf8C/8AQTVCr/hn/kOQf8C/9BNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/rgn/oT1eqj/wAzE3/XBP8A0J6vUAFFFFAEN9/x6v8ASmaN/wAge1/64p/6CKfff8er/SmaN/yB7X/rin/oIoAs0UUUAFcx8X/+RJ/7iFh/6WQ109cx8X/+RJ/7iFh/6WQ0AZVFFFABRRRQAUUUUAFX/DP/ACHIP+Bf+gmqFX/DP/Icg/4F/wCgmgDraKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP/ADMTf9cE/wDQnq9VH/mYm/64J/6E9XqACiiigCG+/wCPV/pTNG/5A9r/ANcU/wDQRT77/j1f6UzRv+QPa/8AXFP/AEEUAWaKKKACuY+L/wDyJP8A3ELD/wBLIa6euY+L/wDyJP8A3ELD/wBLIaAMqiiigAooooAKKKKACr/hn/kOQf8AAv8A0E1Qq/4Z/wCQ5B/wL/0E0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/5mJv+uCf+hPV6qP8AzMTf9cE/9Cer1ABRRRQBDff8er/SmaN/yB7X/rin/oIp99/x6v8ASmaN/wAge1/64p/6CKALNFFFABXMfF//AJEn/uIWH/pZDXT1zHxf/wCRJ/7iFh/6WQ0AZVFFFABRRRQAUUUUAFX/AAz/AMhyD/gX/oJqhV/wz/yHIP8AgX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/AMzE3/XBP/Qnq9VH/mYm/wCuCf8AoT1eoAKKKKAIb7/j1f6UzRv+QPa/9cU/9BFPvv8Aj1f6UzRv+QPa/wDXFP8A0EUAWaKKKACuY+L/APyJP/cQsP8A0shrp65j4v8A/Ik/9xCw/wDSyGgDKooooAKKKKACiiigAq/4Z/5DkH/Av/QTVCr/AIZ/5DkH/Av/AEE0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/5mJv8Argn/AKE9Xqo/8zE3/XBP/Qnq9QAUUUUAQ33/AB6v9KZo3/IHtf8Arin/AKCKfff8er/SmaN/yB7X/rin/oIoAs0UUUAFcx8X/wDkSf8AuIWH/pZDXT1zHxf/AORJ/wC4hYf+lkNAGVRRRQAUUUUAFFFFABV/wz/yHIP+Bf8AoJqhV/wz/wAhyD/gX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/zMTf9cE/9Cer1Uf8AmYm/64J/6E9XqACiiigCG+/49X+lM0b/AJA9r/1xT/0EU++/49X+lM0b/kD2v/XFP/QRQBZooooAK5j4v/8AIk/9xCw/9LIa6euY+L//ACJP/cQsP/SyGgDKooooAKKKKACiiigAq/4Z/wCQ5B/wL/0E1Qq/4Z/5DkH/AAL/ANBNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf8AmYm/64J/6E9Xqo/8zE3/AFwT/wBCer1ABRRRQBDff8er/SmaN/yB7X/rin/oIp99/wAer/SmaN/yB7X/AK4p/wCgigCzRRRQAVzHxf8A+RJ/7iFh/wClkNdPXMfF/wD5En/uIWH/AKWQ0AZVFFFABRRRQAUUUUAFX/DP/Icg/wCBf+gmqFX/AAz/AMhyD/gX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/zMTf8AXBP/AEJ6vVR/5mJv+uCf+hPV6gAooooAhvv+PV/pTNG/5A9r/wBcU/8AQRT77/j1f6UzRv8AkD2v/XFP/QRQBZooooAK5j4v/wDIk/8AcQsP/SyGunrmPi//AMiT/wBxCw/9LIaAMqiiigAooooAKKKKACr/AIZ/5DkH/Av/AEE1Qq/4Z/5DkH/Av/QTQB1tFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/mYm/64J/6E9Xqo/8AMxN/1wT/ANCer1ABRRRQBDff8er/AEpmjf8AIHtf+uKf+gin33/Hq/0pmjf8ge1/64p/6CKALNFFFABXMfF//kSf+4hYf+lkNdPXMfF//kSf+4hYf+lkNAGVRRRQAUUUUAFFFFABV/wz/wAhyD/gX/oJqhV/wz/yHIP+Bf8AoJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/wAzE3/XBP8A0J6vVR/5mJv+uCf+hPV6gAooooAhvv8Aj1f6UzRv+QPa/wDXFP8A0EU++/49X+lM0b/kD2v/AFxT/wBBFAFmiiigArmPi/8A8iT/ANxCw/8ASyGunrmPi/8A8iT/ANxCw/8ASyGgDKooooAKKKKACiiigAq/4Z/5DkH/AAL/ANBNUKv+Gf8AkOQf8C/9BNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/rgn/oT1eqj/AMzE3/XBP/Qnq9QAUUUUAQ33/Hq/0pmjf8ge1/64p/6CKfff8er/AEpmjf8AIHtf+uKf+gigCzRRRQAVzHxf/wCRJ/7iFh/6WQ109cx8X/8AkSf+4hYf+lkNAGVRRRQAUUUUAFFFFABV/wAM/wDIcg/4F/6CaoVf8M/8hyD/AIF/6CaAOtooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo/wDMxN/1wT/0J6vVR/5mJv8Argn/AKE9XqACiiigCG+/49X+lM0b/kD2v/XFP/QRT77/AI9X+lM0b/kD2v8A1xT/ANBFAFmiiigArmPi/wD8iT/3ELD/ANLIa6euY+L/APyJP/cQsP8A0shoAyqKKKACiiigAooooAKv+Gf+Q5B/wL/0E1Qq/wCGf+Q5B/wL/wBBNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/AK4J/wChPV6qP/MxN/1wT/0J6vUAFFFFAEN9/wAer/SmaN/yB7X/AK4p/wCgin33/Hq/0pmjf8ge1/64p/6CKALNFFFABXMfF/8A5En/ALiFh/6WQ109cx8X/wDkSf8AuIWH/pZDQBlUUUUAFFFFABRRRQAVf8M/8hyD/gX/AKCaoVf8M/8AIcg/4F/6CaAOtooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo/8zE3/XBP/Qnq9VH/AJmJv+uCf+hPV6gAooooAhvv+PV/pTNG/wCQPa/9cU/9BFPvv+PV/pTNG/5A9r/1xT/0EUAWaKKKACuY+L//ACJP/cQsP/SyGunrmPi//wAiT/3ELD/0shoAyqKKKACiiigAooooAKv+Gf8AkOQf8C/9BNUKv+Gf+Q5B/wAC/wDQTQB1tFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/AJmJv+uCf+hPV6qP/MxN/wBcE/8AQnq9QAUUUUAQ33/Hq/0pmjf8ge1/64p/6CKfff8AHq/0pmjf8ge1/wCuKf8AoIoAs0UUUAFcx8X/APkSf+4hYf8ApZDXT1zHxf8A+RJ/7iFh/wClkNAGVRRRQAUUUUAFFFFABV/wz/yHIP8AgX/oJqhV/wAM/wDIcg/4F/6CaAOtooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo/8zE3/AFwT/wBCer1Uf+Zib/rgn/oT1eoAKKKKAIb7/j1f6UzRv+QPa/8AXFP/AEEU++/49X+lM0b/AJA9r/1xT/0EUAWaKKKACuY+L/8AyJP/AHELD/0shrp65j4v/wDIk/8AcQsP/SyGgDKooooAKKKKACiiigAq/wCGf+Q5B/wL/wBBNUKv+Gf+Q5B/wL/0E0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/5mJv+uCf+hPV6qP/ADMTf9cE/wDQnq9QAUUUUAQ33/Hq/wBKZo3/ACB7X/rin/oIp99/x6v9KZo3/IHtf+uKf+gigCzRRRQAVzHxf/5En/uIWH/pZDXT1zHxf/5En/uIWH/pZDQBlUUUUAFFFFABRRRQAVf8M/8AIcg/4F/6CaoVf8M/8hyD/gX/AKCaAOtooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo/8AMxN/1wT/ANCer1Uf+Zib/rgn/oT1eoAKKKKAIb7/AI9X+lM0b/kD2v8A1xT/ANBFPvv+PV/pTNG/5A9r/wBcU/8AQRQBZooooAK5j4v/APIk/wDcQsP/AEshrp65j4v/APIk/wDcQsP/AEshoAyqKKKACiiigAooooAKv+Gf+Q5B/wAC/wDQTVCr/hn/AJDkH/Av/QTQB1tFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/mYm/64J/6E9Xqo/wDMxN/1wT/0J6vUAFFFFAEN9/x6v9KZo3/IHtf+uKf+gin33/Hq/wBKZo3/ACB7X/rin/oIoAs0UUUAFcx8X/8AkSf+4hYf+lkNdPXMfF//AJEn/uIWH/pZDQBlUUUUAFFFFABRRRQAVf8ADP8AyHIP+Bf+gmqFX/DP/Icg/wCBf+gmgDraKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP8AzMTf9cE/9Cer1Uf+Zib/AK4J/wChPV6gAooooAhvv+PV/pTNG/5A9r/1xT/0EU++/wCPV/pTNG/5A9r/ANcU/wDQRQBZooooAK5j4v8A/Ik/9xCw/wDSyGunrmPi/wD8iT/3ELD/ANLIaAMqiiigAooooAKKKKACr/hn/kOQf8C/9BNUKv8Ahn/kOQf8C/8AQTQB1tFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/mYm/wCuCf8AoT1eqj/zMTf9cE/9Cer1ABRRRQBDff8AHq/0pmjf8ge1/wCuKf8AoIp99/x6v9KZo3/IHtf+uKf+gigCzRRRQAVzHxf/AORJ/wC4hYf+lkNdPXMfF/8A5En/ALiFh/6WQ0AZVFFFABRRRQAUUUUAFX/DP/Icg/4F/wCgmqFX/DP/ACHIP+Bf+gmgDraKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP/MxN/1wT/0J6vVR/wCZib/rgn/oT1eoAKKKKAIb7/j1f6UzRv8AkD2v/XFP/QRT77/j1f6UzRv+QPa/9cU/9BFAFmiiigArmPi//wAiT/3ELD/0shrp65j4v/8AIk/9xCw/9LIaAMqiiigAooooAKKKKACr/hn/AJDkH/Av/QTVCr/hn/kOQf8AAv8A0E0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/wCZib/rgn/oT1eqj/zMTf8AXBP/AEJ6vUAFFFFAEN9/x6v9KZo3/IHtf+uKf+gin33/AB6v9KZo3/IHtf8Arin/AKCKALNFFFABXMfF/wD5En/uIWH/AKWQ109cx8X/APkSf+4hYf8ApZDQBlUUUUAFFFFABRRRQAVf8M/8hyD/AIF/6CaoVf8ADP8AyHIP+Bf+gmgDraKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP/MxN/wBcE/8AQnq9VH/mYm/64J/6E9XqACiiigCG+/49X+lM0b/kD2v/AFxT/wBBFPvv+PV/pTNG/wCQPa/9cU/9BFAFmiiigArmPi//AMiT/wBxCw/9LIa6euY+L/8AyJP/AHELD/0shoAyqKKKACiiigAooooAKv8Ahn/kOQf8C/8AQTVCr/hn/kOQf8C/9BNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/rgn/oT1eqj/wAzE3/XBP8A0J6vUAFFFFAEN9/x6v8ASmaN/wAge1/64p/6CKfff8er/SmaN/yB7X/rin/oIoAs0UUUAFcx8X/+RJ/7iFh/6WQ109cx8X/+RJ/7iFh/6WQ0AZVFFFABRRRQAUUUUAFX/DP/ACHIP+Bf+gmqFX/DP/Icg/4F/wCgmgDraKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKP/ADMTf9cE/wDQnq9VH/mYm/64J/6E9XqACiiigCG+/wCPV/pTNG/5A9r/ANcU/wDQRT77/j1f6UzRv+QPa/8AXFP/AEEUAWaKKKACuY+L/wDyJP8A3ELD/wBLIa6euY+L/wDyJP8A3ELD/wBLIaAMqiiigAooooAKKKKACr/hn/kOQf8AAv8A0E1Qq/4Z/wCQ5B/wL/0E0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/5mJv+uCf+hPV6qP8AzMTf9cE/9Cer1ABRRRQBDff8er/SmaN/yB7X/rin/oIp99/x6v8ASmaN/wAge1/64p/6CKALNFFFABXMfF//AJEn/uIWH/pZDXT1zHxf/wCRJ/7iFh/6WQ0AZVFFFABRRRQAUUUUAFX/AAz/AMhyD/gX/oJqhV/wz/yHIP8AgX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/AMzE3/XBP/Qnq9VH/mYm/wCuCf8AoT1eoAKKKKAIb7/j1f6UzRv+QPa/9cU/9BFPvv8Aj1f6UzRv+QPa/wDXFP8A0EUAWaKKKACuY+L/APyJP/cQsP8A0shrp65j4v8A/Ik/9xCw/wDSyGgDKooooAKKKKACiiigAq/4Z/5DkH/Av/QTVCr/AIZ/5DkH/Av/AEE0AdbRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBR/5mJv8Argn/AKE9Xqo/8zE3/XBP/Qnq9QAUUUUAQ33/AB6v9KZo3/IHtf8Arin/AKCKfff8er/SmaN/yB7X/rin/oIoAs0UUUAFcx8X/wDkSf8AuIWH/pZDXT1zHxf/AORJ/wC4hYf+lkNAGVRRRQAUUUUAFFFFABV/wz/yHIP+Bf8AoJqhV/wz/wAhyD/gX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/zMTf9cE/9Cer1Uf8AmYm/64J/6E9XqACiiigCG+/49X+lM0b/AJA9r/1xT/0EU++/49X+lM0b/kD2v/XFP/QRQBZooooAK5j4v/8AIk/9xCw/9LIa6euY+L//ACJP/cQsP/SyGgDKooooAKKKKACiiigAq/4Z/wCQ5B/wL/0E1Qq/4Z/5DkH/AAL/ANBNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf8AmYm/64J/6E9Xqo/8zE3/AFwT/wBCer1ABRRRQBDff8er/SmaN/yB7X/rin/oIp99/wAer/SmaN/yB7X/AK4p/wCgigCzRRRQAVzHxf8A+RJ/7iFh/wClkNdPXMfF/wD5En/uIWH/AKWQ0AZVFFFABRRRQAUUUUAFX/DP/Icg/wCBf+gmqFX/AAz/AMhyD/gX/oJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/zMTf8AXBP/AEJ6vVR/5mJv+uCf+hPV6gAooooAhvv+PV/pTNG/5A9r/wBcU/8AQRT77/j1f6UzRv8AkD2v/XFP/QRQBZooooAK5j4v/wDIk/8AcQsP/SyGunrmPi//AMiT/wBxCw/9LIaAMqiiigAooooAKKKKACr/AIZ/5DkH/Av/AEE1Qq/4Z/5DkH/Av/QTQB1tFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFH/mYm/64J/6E9Xqo/8AMxN/1wT/ANCer1ABRRRQBDff8er/AEpmjf8AIHtf+uKf+gin33/Hq/0pmjf8ge1/64p/6CKALNFFFABXMfF//kSf+4hYf+lkNdPXMfF//kSf+4hYf+lkNAGVRRRQAUUUUAFFFFABV/wz/wAhyD/gX/oJqhV/wz/yHIP+Bf8AoJoA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCj/wAzE3/XBP8A0J6vVR/5mJv+uCf+hPV6gAooooAhvv8Aj1f6UzRv+QPa/wDXFP8A0EU++/49X+lM0b/kD2v/AFxT/wBBFAFmiiigArmPi/8A8iT/ANxCw/8ASyGunrmPi/8A8iT/ANxCw/8ASyGgDKooooAKKKKACiiigAq/4Z/5DkH/AAL/ANBNUKv+Gf8AkOQf8C/9BNAHW0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAUf+Zib/rgn/oT1eqj/AMzE3/XBP/Qnq9QAUUUUAQ33/Hq/0pmjf8ge1/64p/6CKfff8er/AEpmjf8AIHtf+uKf+gigCzRRRQAVzHxf/wCRJ/7iFh/6WQ109cx8X/8AkSf+4hYf+lkNAGVRRRQAUUUUAFFFFABV/wAM/wDIcg/4F/6CaoVf8M/8hyD/AIF/6CaAOtooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo/wDMxN/1wT/0J6vUUUAFFFFAEN9/x6v9KZo3/IHtf+uKf+giiigCzRRRQAVzHxf/AORJ/wC4hYf+lkNFFAGVRRRQAUUUUAFFFFABV/wz/wAhyD/gX/oJoooA62iiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA/9k=", - "description": "Allows to create or edit gateway connectors.", + "image": "data:image/png;base64,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", + "description": "Allow to create and manage gateway connectors.", "descriptor": { "type": "latest", "sizeX": 11, @@ -14,6 +14,6 @@ "controllerScript": "self.onInit = function() {\n if (self.ctx.datasources && self.ctx.datasources.length) {\n self.ctx.$scope.entityId = self.ctx.datasources[0].entity.id;\n }\n};\n\nself.typeParameters = function() {\n return {\n dataKeysOptional: true,\n singleEntity: true\n };\n}", "settingsSchema": "{}", "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\":\"8px\",\"settings\":{},\"title\":\"Gateway connector\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":500},\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showLegend\":false}" + "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\":\"8px\",\"settings\":{},\"title\":\"Gateway connectors\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"dropShadow\":true,\"enableFullscreen\":false,\"enableDataExport\":false,\"widgetStyle\":{},\"widgetCss\":\"\",\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":500},\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showLegend\":false}" } -} \ No newline at end of file +} diff --git a/application/src/main/data/json/system/widget_types/gateway_general_statistics.json b/application/src/main/data/json/system/widget_types/gateway_general_statistics.json index 8cf20c1340..349beebc06 100644 --- a/application/src/main/data/json/system/widget_types/gateway_general_statistics.json +++ b/application/src/main/data/json/system/widget_types/gateway_general_statistics.json @@ -1,9 +1,9 @@ { "fqn": "gateway_widgets.gateway_general_statistics", - "name": "Gateway General Statistics", + "name": "Gateway general chart statistics", "deprecated": false, "image": "data:image/png;base64,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", - "description": "", + "description": "Provides a real-time chart with statistical data (all bytes sent to the platform, all bytes received from the platform, etc.).", "descriptor": { "type": "timeseries", "sizeX": 8, @@ -18,6 +18,6 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"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;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Gateway General Statistics\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"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;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Gateway general chart statistics\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" } -} \ No newline at end of file +} diff --git a/application/src/main/data/json/system/widget_types/gateway_logs.json b/application/src/main/data/json/system/widget_types/gateway_logs.json index 5c17b22188..85c631a747 100644 --- a/application/src/main/data/json/system/widget_types/gateway_logs.json +++ b/application/src/main/data/json/system/widget_types/gateway_logs.json @@ -1,9 +1,9 @@ { "fqn": "gateway_widgets.gateway_logs", - "name": "Gateway Logs", + "name": "Gateway logs", "deprecated": false, - "image": "data:image/jpeg;base64,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V6B4kuvEviqC88aeILvTL5dW0vSTY2eny6bKJrIRWrzTMUWUMzh5mMgkZdyjaF9qoo63879tdNV2ei2KstL9P6+e73OC+Dvwk1TwTruveIfE2uWPiHxV4kFvDd3VhprabZxQW6uIYYYGmndQDLKxLSuWaRugCqOGv/2Qtb+3RaXp/jW0sfA9v4th8YQ6S2h+bercC/F/Nbm7M4U27zF2UCEOhYDe6LsPu1FVGTU1NbqzXqmmtNtGl/VyXFODpvZ3v800/wAGzwGw/Y01jSfEmkiPxxbr4T0DxjP40tdNTw+v264nnkuJZori687Eih7l9jJCjqFUOZcVH+zd8Gm1PX/i54ws28T+F7f4hX/laGbuzazvtLtlhzJcR29xGGhaS9mu5gkqZOVYrhgK+gqKmKUb26pr7+VN33vaMV6eZcpNvmfdemjk1ptvJs8r+Cf7PWqfD34l694v8Qa5oera5rlnBp8p0XQP7Gt544nkdZrhDPO01yfMIMm5VCjCovOfVKKKOiXb/hxW1b7/APDfkgooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAPn39tXxNrmsfEj4R/DfSfEGreFbD4iaxdx6vqWlT/Z78W1raPOYIZsZiaRgoLrhgoIBGc15j4a/ay8P/ALMfw1+MmoaL498Z/Ei18FpaXFl4f8U6bqUep6RNcOYEjN7dRia6glmGVIV2QK2C2VFfSnx+/Z20H9ovw7p9nrE2rabfaLepqWk6tpN19l1DSLpQVEsMmCAdrMpVlZWDEFTXG6H+wR4OTw543svEmpeKvHd58Q7SKw1vU9ev1e7ngh3eSieQkUUXllmZTHGrBjkk8V6lGvh1SUal/NJLX3r3v6abp6dmefVo1nUcoW8nrppa3367NfNHi15/wUH+KPhn4MfEbVL7wvpt5qnhWy0++0rVpvCmt6BpF69xdLBLaPDfhJmkiyG8yNirBwdowVO/4t/b18afs/Q/F2z+IGk+FdW1XwHomma7pR8Px3UMF2t/LLbxW8qyNI5ZJo8F0HzKchAflr0WX9hDSdZ+FGv+Edf8ffE7xVZ+II7SB7rV9Yimns4raVZY0hVYVhUll+Z2jaRx95zgY3PHX7Gng34meLPG2q66mpagvj7QLTw5qdm86rbrb2zzSRPFtUSJKGmY7t5wVQgAg509vg72cdL9P+3fT+8R7HFWupa2/wDkv+AeBXX/AAUE+KHhn4G/FLWdQ8M6fd6n4N0i01XSdWl8J63oOk30k04iktHhvwkzPHwd8b7WDg4Ugqe0+Nf7S/xQ+DvhHwnY6hf/AAztvGet297fXMFloet680kcWGjjt7G0BuGQBlWW5d1RDghDuCjrpf2EtK1n4P8A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gAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAMvxh4K0f4haBNpWvaXp+saZcFWktb2BZ4ZCrBlJVgQcMAR7itKKNYY1RFVUUBVVRgADsKdRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAHlWs/sS/DDxD8Z4fH994YF14khvE1NS+oXRsPtqKES8Nj5v2RrlVVQJzEZRtGGGBXqtFFC0iorZdA683UKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKjunlSBjCkcknZXcop/EA/yqSigDP+1ap/z52H/gY/8A8ao+1ap/z52H/gY//wAarQooAz/+Ekt/+eeof+AM/wD8RR/wklv/AM89Q/8AAGf/AOIrQooAz/8AhJLf/nnqH/gDP/8AEUf8JJb/APPPUP8AwBn/APiK0KKAM/8A4SS3/wCeeof+AM//AMRR/wAJJb/889Q/8AZ//iK0KKAM/wD4SS3/AOeeof8AgDP/APEUf8JJb/8APPUP/AGf/wCIrQooAz/+Ekt/+eeof+AM/wD8RR/wklv/AM89Q/8AAGf/AOIrQooAz/8AhJLf/nnqH/gDP/8AEUf8JJb/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FFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFHX/Dtt4jtPKuFOV5R1+8h9q5G5+E14sh8m6t3XsXyp/QGu8ooA8+/wCFUaj/AM9rL/vtv/iaP+FUaj/z2sv++2/+Jr0GigDz7/hVGo/89rL/AL7b/wCJo/4VRqP/AD2sv++2/wDia9BooA47RvhSsUwe+nWRV/5Zx5Ab6nr+VdfFEsEaoihVUYUAcAU6igAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqO6tIr6Bopo45o2+8jqGU9+hqSigDP/4RPS/+gbYf+A6f4Uf8Inpf/QNsP/AdP8K0KKAM/wDse4/6C2of98Qf/G6P7HuP+gtqH/fEH/xutCigDP8A7HuP+gtqH/fEH/xuj+x7j/oLah/3xB/8brQooAz/AOx7j/oLah/3xB/8bo/se4/6C2of98Qf/G60KKAM/wDse4/6C2of98Qf/G6P7HuP+gtqH/fEH/xutCigDP8A7HuP+gtqH/fEH/xuj+x7j/oLah/3xB/8brQooAz/AOx7j/oLah/3xB/8bo/se4/6C2of98Qf/G60KKAM/wDse4/6C2of98Qf/G6P7HuP+gtqH/fEH/xutCigDP8A7HuP+gtqH/fEH/xuj+x7j/oLah/3xB/8brQooAz/AOx7j/oLah/3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x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbo/se4/wCgtqH/AHxB/wDG6ANCis/+x7j/AKC2of8AfEH/AMbqS102a3nV21C8nVeqOsQVv++UB/I0AXKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiuW8feNX0dvsdo224YZd/wDnmOwHua4S5vJr2TdNJJKx7uxY0AeyUV4vRQB7RRXi9FAHtFFeTaR4mvdEmVoZ32g8xsco34V6Z4f1uPxBpcdzH8u7hl/uMOooAu0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRVfVtVt9D0q6vrqTyrWzieeZ9pbYigsxwMk4APA5rH+FfxP0f40fDzSfFXh99Ql0XXIBdWUl7ptzp00sR+65guI45VDDlSyDcpDDIIJFre3S1/K97ffZ272fYG7WT63t8rX+66v6rudBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRXK/Gj40+H/ANn7wBdeKPFM2pWuh2BX7VcWelXepG2Un/WPHbRyOsa9WkKhEHLEDmuqVty5HQ80dL/L5/0194dbBRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRVLQfEuneKbWa40vULLUoLe4ms5ZLWdZljnhkaKWJipIDpIrIynlWUggEEUB0uXaKKqa/r9j4U0K91TVL2003TNNge6u7u6mWGC1hRSzySOxCqiqCSxIAAJNA0m3ZFuiozewrZ/aDLGLcJ5hl3DZtxndnpjHOah0LXbHxRolnqWmXlrqOm6hAlza3drKs0FzE6hkkR1JVlZSCGBIIIIoFdFqiiigAorHg+Inh+61hdPj1zR5NQe7ksFtlvY2ma5jiE0kITOfMWIh2TG4KQxAHNbFAlJPYKKKKBhRRRQAUUUUAFFFFABRRUOo6lb6Pp9xeXlxDa2trG0000ziOOFFGWZmPCqACSTwAKUpJK7BXeiJqKh0/ULfVrCG6tZobm1uY1lhmicPHKjDKsrDgggggjgg1NTaadmCaaugoorJ8cePND+GPhS917xLrWk+HtD01PMu9R1O7jtLS1XIG6SWQhFGSBkkckUm0ldgk27I1qKjtbuK+tY54JI5oZlDxyIwZXUjIII4II5yKkp7aML31QUUUUAFFFFABRVPxF4j0/whoV3qmrX9npemafE091d3c6wQW0ajLO7sQqqBySSAKuA5FABRRRQAUUU2SVYV3MyquQMk45JwB+J4oAdRRRQAUVRt/E2m3fiK60eLULGTVrGCK6ubJJ1a4t4ZWkWKR487lR2ilCsRhjE4GdpxeoAKKKo6l4l03RtQsrO81CxtbrUmdLSGadY5LpkQyOI1Jy5VFZiBnCgk8Chu2rAvUVT8O+I9P8X6BZatpN9Z6ppepQJdWl5aTLPb3UTqGSSN1JV0ZSCGBIIIIq5TaadmAUUUUgCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK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56h/4Az/APxFH/CSW/8Azz1D/wAAZ/8A4igDQorP/wCEkt/+eeof+AM//wARR/wklv8A889Q/wDAGf8A+IoA0KKz/wDhJLf/AJ56h/4Az/8AxFH/AAklv/zz1D/wBn/+IoA0KKz/APhJLf8A556h/wCAM/8A8RR/wklv/wA89Q/8AZ//AIigDQorP/4SS3/556h/4Az/APxFH/CSW/8Azz1D/wAAZ/8A4igDQorP/wCEkt/+eeof+AM//wARR/wklv8A889Q/wDAGf8A+IoA0KKz/wDhJLf/AJ56h/4Az/8AxFH/AAklv/zz1D/wBn/+IoA0KKz/APhJLf8A556h/wCAM/8A8RR/wklv/wA89Q/8AZ//AIigDQorP/4SS3/556h/4Az/APxFH/CSW/8Azz1D/wAAZ/8A4igDQorP/wCEkt/+eeof+AM//wARR/wklv8A889Q/wDAGf8A+IoA0KKz/wDhJLf/AJ56h/4Az/8AxFSWutw3k6xql4rN0L2ksa/mygD8TQBcooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKrarq1voto01xII4xx7sfQCuYufi5Ckn7mykkX1eQKfywaAOwori/+Fvf9Q/8A8j//AGNH/C3v+of/AOR//saAO0ori/8Ahb3/AFD/APyP/wDY0f8AC3v+of8A+R//ALGgDtKK5rSPidZahMsc0b2rMcAsdyfn2/KulByKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAo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mSnc8m0AbmPcnGTWs1BXUXezdntdXdtOiStbvfdtMh7prsrrzsru/m7u3S3ZosUUUVkMKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAo6/4dtvEdp5VwpyvKOv3kPtXI3PwmvFkPk3Vu69i+VP6A13lFAHn3/CqNR/57WX/AH23/wATR/wqjUf+e1l/323/AMTXoNFAHn3/AAqjUf8AntZf99t/8TR/wqjUf+e1l/323/xNeg0UAcdo3wpWKYPfTrIq/wDLOPIDfU9fyrr4olgjVEUKqjCgDgCnUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQBn/ANj3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N1oUUAZ/wDY9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdaFFAGf8A2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43WhRQBn/ANj3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N1oUUAZ/wDY9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdaFFAGf8A2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/4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RxNa280wkj8uKaVHk82Parb1zXK20lrft37evkVKLi2n0SfyaTv+KPR6K8t8J/tn/Djxv8QLXwzpuuXs2qXuo3ujwSPot9DYzX9m8yXNmt28ItzcJ9nmbyfM3skZdVZCGPM337b+i+Jfjd4P8KeEZn1K31i+1S0vru50W+gtZhZ2c0payupES3uQs0ao7QtKoyRlTg1nKajHme1m/ktyZe67S3ul827W+894or5/+Fn7fXhWX4E/DXXvHWpR6X4h8ZeFdN8RalDpmk3t1Z6Ql1CrGe5eJJVsrUyeYqzXUiJ+7YbyVbHXav8Ato/DfQ/EfirSrjXLz7Z4JkS31oxaNfTQ2c8gtjFbeakJjkuJftdv5UEbNLKZMIjFWA2qUZQnKm94tp/9uuz+57hre3XT8dvv6dz1KiuF+H37R/hP4o6bp91otzq841DUZNI8ifQ761urC7SFp2iu4JoVls28pdw+0rGDvjxkyIG89/a+/bQm/Zo8f+D/AA5aQ/DWO68VWl9efbfG3jc+FdPh+zy2kSwpKLO682aVrv5Y9q8ROcnpUWd1Hq9vPS/5ajiua9ul393/AAVb103PfKKp+H7m8vdBsptRgs7XUJYEe5htLlrm3ikKgsscrJGZEByA5RCwwdq5wLlEk07MmMrq6CiiikMKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK8F/an8A/Ff4h/EXQYfD3hv4eeKfh7psaX13pet+LrzQ5dQ1FJC0fniHTLxZbaMKjiPcu6TBcFUAPvVFK2qfb+v8Ag+tmO+jXf+v+B6aHzL8U/wBmH4ieOT4+0myh8E2vh/41W9m3imaXVrprzw7cLaRWd19jQWu29V4IIhGZGtdrKWKsDsGlrHgH4zX37VR8TXnhb4Z+IvCWj3CW/hk3Hja+sbjRbZ0CXN2bJdKljlvnDSqGNwFWLEaGPfM8n0RRVJtNNdL6ettPklZeQndp36pL7v8APr0+R843v7LvjDxf+0npXinWtN+HtlJol9O48b6PLPaeJ9Y0thcCPR54UgULAgmTLm7lDNAsiwxy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A8Z+J7fW9MsdWkuWtmt4bTToRHLKgEsE++zcxzx+aYWMUoDspSvfKK2lWlKU5ved7/OSlttuuq7p3RMtXFv7LuvWzX4p9Oye547+zR8OviP8KfCyWfiC40vUI9Q1uS5eym8TX+tSeHNPNqqrBDf3UAuNQc3Sb91wItqXDKCREitqfHnw34+v9Ut7rwbpfgHxDbXGn3Gl32neJriWxWNZWQ+ck8VtcNIu1Sr2zIqyfIfMTbz6dRWdRKatLa1vlbl173W73vre+oRbjqv6d73+/wCVtLWvfkfgD8Lm+CHwM8G+DW1CTVm8J6LZ6Qb2RdrXZghSLzCuTt3bc4ycZxk9a66iirqVJVJuct27v5kxioqyCiiioKCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/8boA0KKz/wCx7j/oLah/3xB/8bo/se4/6C2of98Qf/G6ANCis/8Ase4/6C2of98Qf/G6P7HuP+gtqH/fEH/xugDQorP/ALHuP+gtqH/fEH/xuj+x7j/oLah/3xB/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W1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdH9j3H/QW1D/viD/43RRQAf2Pcf9BbUP8AviD/AON0f2Pcf9BbUP8AviD/AON0UUAH9j3H/QW1D/viD/43R/Y9x/0FtQ/74g/+N0UUAH9j3H/QW1D/AL4g/wDjdH9j3H/QW1D/AL4g/wDjdFFAB/Y9x/0FtQ/74g/+N0f2Pcf9BbUP++IP/jdFFAB/Y9x/0FtQ/wC+IP8A43R/Y9x/0FtQ/wC+IP8A43RRQAf2Pcf9BbUP++IP/jdNbSrgf8xXUP8AviD/AON0UUANOm3P/QV1D/viD/43TRp9yf8AmK6h/wB8Qf8AxuiigB66ZcH/AJiuof8AfEH/AMbqe006aCdXbULydV6o6xBW/wC+UB/I0UUAXKKKKAP/2Q==", - "description": null, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAABblBMVEXg4ODf39/g4ODg4OAAAAD////l5eXg4OD39/fs7Oz/5ebo6Ojz8/P/9ubd3d3Ly8u6urqpqamGhobu7u7/8vKYmJh1dXWxsbGXl5egoKD//fp+fn7U1NTCwsL4+PiPj4//+OzurrGelZH0ycuoqKjdXWTXQkrRJzD88vL55OXOysnDw8Pok5fztbjroKTieH3ibXP9/f1ZRD75zdCHenX6t1VBKSLXPkbx8fH+7dHunqKOjo7ohotwX1nUND37wWr319jZ2NfZT1cqDwb82dvxvL7Cvbu2r635rkH+8tz3wcT+4LLlhYr/6uv95L3926jlhov6+vqqop/7yX/dVl36skv//PX88fL+8dz8153/9+qTh4N8bWjaSlI2HBT+7dLwvL7xqa3rkpZ8bGf/+fD+6cf+5L3tnaHok5j80pP7zongYmhYRD3UMzv65OWfn5/7vGBkUkv/9PTw8PD7yX7jeH5NNzD0trlkUUv0trh+scVYAAAABXRSTlPvIL+vAC9A4IoAAAsOSURBVHja7JfBa+JAFIfTbd9zgmVmnCGZSGYIBE/xZBARpAcp6Ll7beml18IiC8v++fuiMaur6ZLuHqLkQ8PkTeYHH/PU0bu7+eL1Lp3bmzvvxvs+gQtnMieN2zlcAZra6uL3o2DieT24CnqdSMvoRNpGJ9I2TkQm8z6epa+foMX8KXKP9fTvoRlugfA/WJimIuTxIQ1NpDz2YmwMf8EXcIoYnE0HNq4TecKP6U8aivjcCV9y8KXlPBYi5kAwJxhwiWC59MFautDdtiwVMueoKDT4lgoCfF6J7OIQKJLz0B7GHYto3LF+W+YZPqfrPM9X2SZPsWTeUIQruxjyGJQxASprYw3E0MihSKzikXExhM4YmlNsYYxxiR4ZF0AoNQhazCPuBpVIETeyFCcpLsQyLqJ14likjzvSPHvM8WGabrJsOXtezdb7LWkqEsBAgMIYaKS0VlAQAmgqm3HEaRxS68hkoERMZU4OQE+Gu45y0plouyNWDQF2cSHFbJ87jDsWwQOR96+FyHq9ekV8e8GSz4qwQ5GY+cJIGIlKxA00sqLMA5qlVykykixW+89IJcLiSqSKqxfJZptpOnt4Wc0Qp/8ooqVSAURDpgwQTiVWqyRglQhTQcKcUpYpSbOSikaKOFAaInMiAjJZ7OIkEMU6Xd9aOH2cpg+Iy9cM39PPtdY3BiXFjgDdYRRFDlhR13AIVahcvvdfVsV4oWG0F4H6uGOR+aHIckYi25sfP7FEQxNQ6N9jA02xji5mTEYcKurijkUmeJZlNWrvv8mmP4it5eSIcqEeZw6Nuu7QOG9vX131Mf5S6UTaRifSNnrekl0FPU/0r4Iraq1OpF10Im2jE2kbncgvds2eR20gCKDVjGZFtB9emd2VbVY6ucJVUlgnnSiuOepzS5SGFildfn/GOImBGOfMUThRHhISgxjxcAH2Y24MiHx8XQ3wOuvzwwGRlcAriBVMhCzcBUvTRR5xhEeYhk7u1EfMZBH2mGAysY8YSwH+ALo395EUKNzaR3A1UQSdKVUoAIOuVFaWmQJGmFKADgp0FXJwOggogjqOQ5YLEwQPEaQODgyh/iXyc51s1y3d6brhPtJs1lwS9rumruuXbV3vb+8jNjjMKJFFyncyIWCepAoqIMePCrmPoDMqWC8TyTopedUOcwIVra+8dFUrQpYAeJ13uIQEdUpL+2Nd+7qRPvINN92133qNh+Z9fUQml32kHWvd95HExzzj8UUf0VqZJ9uKSKNH+giM9JH9jkU+PTTbe2SFTJz1ESEq7SDkfR8pQRzHMvLxEgkPSagApaIk/t5HEtGK0Om66yLP9eEo8q4+gg60hECF/5qCCxCDlBJlDEjGa3AInm95AS6mNvc8jgXGqHhYKBV9SmBUL9Kt4+e853UpRd2uO77uXESciOCu6yP4ZftcN9ghpolEC9B/mC1kjFHwJrr3L9vWY6BncN21PtJ8Xh8QNw/Njh+8HOrdbZexydJ4dx4Hc74r1OAXolDjfWSBoyzm+zvlXARWOMqM/8RxLjJ+TBYz9rgUYT6IYSzBnPmXz0f+Tv6LzI3v7JnBa4MwFId3eYw9duxJdglBY8DEQA6CFBHRi7SQg7CT4HoqlJ7H/vu9tmvZit1wDCbiBwnPp/nBx/OWWWRs3N89PU4Cuh95mAQT+rVmkXExi4yNWWRsTFjEWwzFgxFwLeKtcTjrEahciXj4O/7fhER65jGYNfShixz+gmI1VGSBJ0qllFWItUWrSlpKUaum/rEqqbC0jh+cWEAPUfTVK3zW8AOS9TRZ3JsOFHdD5DyQNDHmrdlYYZfJrrWmNaYWpmleTdJSZV+SXVIrobBJvxkJiUiumYw4yKjjPGMs40CEmoXAoxw6HknoOtro6diOgjzUmppMguw0e2Yg+UXkFJcDRXIuuk9xVyJ4FmloU/vdEpMaN6lZIlqBuLd4KIVtU9w0SiTlRQT7RXhQFYZnEDjn50FVZRII47aGFVXAfaczENqt6F0QFs6tdCFjp30QWwmMDnOf6/gicoiLK4rbUpzIP+J8OsduiLyzZzYtDsJAGD7NJef9A1IyGtAY8BAQERG9SA57WPDkwV4slPZQKPv3d1I/tmx3W3pYcF1fVCYzMvAwExOMqzVj+0PBXDtUB60it0t0MYDoiAU60OfkIQiH0AHMUiALhUCwcgGO5DaSb8h2qXX8PEQnJfeG2ygKt+8o6UvDLxUpUQH06VxKc3nvOt1ta00ViXTT2SJUVV+ROC7YCBKw4C3QhW6m1noA4l2DpJ5wjE+RCUSGx8yz7g2nKF0DSOjXKY5zZAKp0wlkSvf9ZI9110XqHByKvWp1q/ZdV9najCDbpm3iQFPlRpDTXRCxQ+TAVY2vQJKYlwJz7k0gNfLck4hljT5Fd+Q0vpNyFMDNDQjs8rxP5/fpsBRf/sYPJamSJGmTiG0rFp/fWUvDKGFWbcBYUrBYxSzaMnrh3pLoK280bUWARhnnXIJn/Ue4FnnIPdzjx8rauYBwBIGf0v3ygpg54tM28KxKSQ8jiWhzm9r8ky2KRTm9PKfTDDAWvY3/o1pB5qYVZG5aQeamBR0rLOagZzGttYLMSyvIB/tmryIxCIXRasqvX6bKS9zCylYRtBBF09gkgaRKkfdnndGdItVkYeEy7MGf+hSiIIcb/yLc+GCROE3Dm0zxxoazSMQlRjYqJ5GIq0SW/cgdlxnvHPuRCY3ZwggY/VjhXF3rEDa5tkPnLNCZOPYjIxpGYl+TQgoSUJsnTRJOCoXH7kHbShqNkWM/gk4KVcFKuKoAJRAEhdxEyDhfPWE0Or/uR77+rh/BD5S3fd0gzZah5C5BjvJTxFL2TsL7gg7HfmRA5wjLQUYoChJqkStoWekpIlbydkehBY2BYz8S0clKO1WyB8KiRAmaFnSRRB77sYUZjcixH3md9jQjWcwadVrAaqtR5mRhgVIA415nnWU/cruPl68Rlv1INZlwBTYvlJNIc3kbFh8jn/+M/27vbFrbBoIw7HzMZHUZjbQokthNBUYn+eQgTKDkoIt877Uhl/6AUAKlP7/rVWNkb+o6rikroRf8sTNo4EErhHR434FqAvFNE4hvmkB804hsqUZjFDaarTWB+KUJxDdNIL5pAvFNLoiQwfvy2UjaBfl0Ts8HHUk4h6LwJBeO85FwKna4hNDwFwUErhYRvKMQhP5PvijMApEEBWA+GCitY7QNJIBNGQPzRaJb2fJdEdguoQCBaLqmFb6B7Iy7pd44C+Karbfzpm7wy7qt67pqvj5VJ9tSqTQu0hjyqEy0YlYajNIoXwQFFyIrogJUlLFdbcplTJxHCagEISw4pthgbEFIcZyZcfFm3O2iNw7/7B30Da2b07z68TRfvZEEZ4rtEDpd7MR2vIRZuCnbtIt+bAdzbs8IJamTdtEbd8CWarXu/LVsbEd91vwRJQBNueyB5ERCgcC92A5mmbixHTLeB8EDIOt7A/K8urf+Wo//6K+VlVkCn1mo0NbLF8YiLeQWRBacybLMGJW+y8vUFDkMY7av4h0Q2I7rtpY5jg7Edjw+/47taPD7ibEdZYCAAgiAdAISQVKSJAyEYP6KrkcgpV3ZMsnuB6QIo02xJEi3F/v+ONyO2wV57YM0HQjWq5+r6qTYDuJebEcOH5VOwXAkAKydnjPOgji3kapt1ohtVVmAtm0GF9vxgAflcSqn45w5UI4Pepl6rKPdZZf+Xh5jfx4ZqEYEMvN88x+n5c3s8hVGoIcrkz7tdxzSMVpKg3F9cXUzdM0uL65/AVWlQEjXqFpfAAAAAElFTkSuQmCC", + "description": "Allow to monitor and analyze the gateway logs.", "descriptor": { "type": "timeseries", "sizeX": 7.5, @@ -15,6 +15,6 @@ "settingsSchema": "{}", "dataKeySettingsSchema": "{}\n", "settingsDirective": "tb-gateway-logs-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"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\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":0,\"realtime\":{\"realtimeType\":0,\"timewindowMs\":86400000,\"quickInterval\":\"CURRENT_DAY\",\"interval\":300000},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Gateway Logs\",\"showTitleIcon\":false,\"dropShadow\":false,\"enableFullscreen\":true,\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showLegend\":false,\"useDashboardTimewindow\":false,\"displayTimewindow\":true}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"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\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":0,\"realtime\":{\"realtimeType\":0,\"timewindowMs\":86400000,\"quickInterval\":\"CURRENT_DAY\",\"interval\":300000},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":false,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{},\"title\":\"Gateway logs\",\"showTitleIcon\":false,\"dropShadow\":false,\"enableFullscreen\":true,\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showLegend\":false,\"useDashboardTimewindow\":false,\"displayTimewindow\":true}" } -} \ No newline at end of file +} diff --git a/application/src/main/data/json/system/widget_types/gateway_statistics.json b/application/src/main/data/json/system/widget_types/gateway_statistics.json index 1eb24c4482..b72377c771 100644 --- a/application/src/main/data/json/system/widget_types/gateway_statistics.json +++ b/application/src/main/data/json/system/widget_types/gateway_statistics.json @@ -1,9 +1,9 @@ { "fqn": "gateway_widgets.gateway_statistics", - "name": "Gateway statistics", + "name": "Gateway custom statistics", "deprecated": false, - "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAkACQAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAFSBl0DASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKBwKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiimyLvQ84PY0AOoqKyn+02sb/3lBqWgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooqlr0rR2IwcbmAP05oWrAu0Vy9FachPMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvRRyBzHUUVy9FHIHMdRRXL0Ucgcx1FFcvQrFTkcH1FHIHMdRRUdo5ktY2PUoCfyqSsyiro3/ILg/wBwfyq1VXRv+QXB/uD+VWqACiiigAooqj4l8S6d4M8PX2r6xf2WlaTpkD3V5e3k6wW9pCilnkkkYhURVBJYkAAEmhuyuwSbdkXqK8l8H/t8/Ar4h+KLLRPD/wAafhNrutanKILPT9O8X6fdXV3IeiRxJKXdj6KCa7z4ZfEzQvjJ4D03xP4Z1GLVtC1iLzrO8iVlSdMlcgMAeoI5HajXcV1exvUUUUDCiqPiXxLp3gzw9favrF/ZaVpWmQPdXl7eTrBb2kKKWeSSRiFRFUEliQAASasafqEGrWEN1azRXNtcxrLDNE4eOVGGVZWHBBBBBHXNAE1FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUVg6n8UvDOiePtM8KXniLQrTxRrUElzp+jzX8Ud/fxR8ySRQFvMkVP4mVSB3o62Dpc3qKw7v4neG7D4g2nhKfxDocPiq/tHv7XRpL+JdQubZDteZIC3mNGp4LhcA963KOlw62CiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACqHiH/jyX/fH8jV+qHiH/AI8l/wB8fyNOO4nsY1cx8YfEOq+Fvh/eXujQST3kTRgmO1a6eGIyKJJVhX5pGRCzBBySOh6V09ZXjPw1J4r0M20Go3mlXCyJNDdWxG+N0YMMg5DKcYKnggkVuQeUx/HvV9I8Dw6npl1pvj2zutesdLgu7XZbzxpNKkcqXERZAkyFiAOPvLuUYOe71b4wQ6J4zttJudJ1WKO7ulsYr11jWF5mjLhVBfey8Ebwu3IIzxWJP+zudQtNWnu9euJdc1fUrHU5L2O0jjjjezZGhRYRxt+T5ssWO4/MMABNQ/Zug1D4nR+I21VsxapHqyxNYwvKJFj8sxidgXWIjkKuMHPJHFICt4S+O+o+IdN0KbUdOl0aXU/FF5oix+XHOJ0h+1YOVlynEAy3zfMDhcHIl/4aObXfhzrWvaL4e1W4jsbCW9s3laDyrrYSCpxLmNhjJR9rYB4yMVoWHwHjtH09X1a5lt9K8QXGv2qeUqsjTrPviLDqA1w5BwCMAc9ap6J+zfDp9xq0l1rNzeSanpkulGYW0UMzxv1kndR+/mGAA7AcZ4ySaAHy/HlNE1TUf7Ut7yD7Ho+nXp09LdHl866mliSNZFlIdmdFXbgAcHecnb1/g7xZN4ojuhc6Pqui3FnII3ivUX58qGDI6MyOvOPlY4IIOK5TUv2eodf+3y6hq91LfX+mWFibmGFIjBLZzSTRXCKdw3eY4O05HyDrk11Xgzw1f+H4rt9S1q51q7vJRIzvGsMUAChQkca8KvGTkkksTnoAwNuiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA6Ox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+VS1FY/8eUP+4v8AKpa5zQq6N/yC4P8AcH8qtVV0b/kFwf7g/lVqgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqh4h/48l/3x/I1frnPib420bwHoMV3rmraZo1pJcCFJ766S3jZyrEKGcgFsKxx1wD6U47iexFVTXdBsfFOjXWnanZWmo6fexNDc2t1Cs0NxGwwyOjAqykdQRiuW/4aP+Hn/Q+eDP8Awd23/wAXR/w0f8PP+h88Gf8Ag7tv/i63IJfBX7P/AID+G1j9m8O+CfCOgW32NtP8rTdHt7VPszMXaDbGgHlliSU+6SScVqaT8NfDmg3ul3FjoGiWdxodidM06WCxijfT7Q7M28JCgxxHy48ouF+ReOBWN/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0gMnwn+xl8HvAXjr/hKNC+FHw10XxN5rz/ANr2Hhiytr7zHOWfzkiD7mJyTnJNTan8Er/xR+0JpvjLWdfivNI8NW8q6BokOnCIWVzMgjmuppzIxmfZuRAqRhFkfO8kEaH/AA0f8PP+h88Gf+Du2/8Ai6P+Gj/h5/0Pngz/AMHdt/8AF0AbWtfDjw94k8WaVr2oaDot/rug+YNM1G5sYpbvTvMG2TyZWUvHuHB2kZHWs0fAfwOPicfG3/CGeFP+EzMfknX/AOyLf+0ymMbftOzzcY4xuxVf/ho/4ef9D54M/wDB3bf/ABdH/DR/w8/6HzwZ/wCDu2/+LoAn1f4CeBfEHxItPGN/4L8J3vi+wUJa65caRbyalbKOgS4ZDIo9g1N+Jv7P3gL41XVhP4y8EeEfFs2ltvspNa0e3v2s265jMqMUPuuKi/4aP+Hn/Q+eDP8Awd23/wAXR/w0f8PP+h88Gf8Ag7tv/i6ANbxx8LPDHxO8GyeHPEnhzQfEPh6ZVSTS9T0+K7s3VfugwyKUIHbjimad8JvCuj6Loum2nhnw/a6d4bmW40i1h06FIdKkVWUPAgXbEwV3AKAHDMO5rM/4aP8Ah5/0Pngz/wAHdt/8XR/w0f8ADz/ofPBn/g7tv/i6AOjXwfpKXup3I0vThc60iR6jKLZN9+qqUVZWxmQBSVAbOASOlZ+i/Cbwr4b+HzeEtP8ADPh+w8KtDJbNo1tp0MWnmKTPmRmBVEe1tzbhtwdxz1rM/wCGj/h5/wBD54M/8Hdt/wDF0f8ADR/w8/6HzwZ/4O7b/wCLoA6W98L6bqXhx9HuNOsZ9Ilg+yvYyW6tbPDt2+WYyNpTbxtxjHFY/gj4KeDfhn4Ln8N+G/CXhnw/4duQ4m0vTdLgtLKUOMPuhjUIdw4ORyOtUv8Aho/4ef8AQ+eDP/B3bf8AxdH/AA0f8PP+h88Gf+Du2/8Ai6AIfhL+y98M/gFd3E/gX4d+BfBU92u2eTQdBtdNecejGGNSw471f8d/AjwP8U/EGl6t4n8G+FPEeq6G/mabe6ppFveXGnt13QySIWjPupFVv+Gj/h5/0Pngz/wd23/xdH/DR/w8/wCh88Gf+Du2/wDi6AOl1jwtpniG50+a/wBOsL6bSbj7XYyXFukrWc21k82IsCUfa7ruXBwzDOCaF8LaYviZtaGnWA1lrYWTX4t0+0mANvERkxu2bju25xnnGa5r/ho/4ef9D54M/wDB3bf/ABdH/DR/w8/6HzwZ/wCDu2/+LpgW/CfwN8FeAvGOqeItC8H+FtF8Qa4d2panYaTBbXmoHOczSogeTn+8TTB8B/A4+Jx8bf8ACGeFP+EzMfknX/7It/7TKYxt+07PNxjjG7FV/wDho/4ef9D54M/8Hdt/8XR/w0f8PP8AofPBn/g7tv8A4ukBPq/wE8C+IPiRaeMb/wAF+E73xfYKEtdcuNIt5NStlHQJcMhkUewautri/wDho/4ef9D54M/8Hdt/8XR/w0f8PP8AofPBn/g7tv8A4ugDtKK4v/ho/wCHn/Q+eDP/AAd23/xdH/DR/wAPP+h88Gf+Du2/+LpgdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0AdpRXF/8NH/AA8/6HzwZ/4O7b/4uj/ho/4ef9D54M/8Hdt/8XQB2lFcX/w0f8PP+h88Gf8Ag7tv/i6P+Gj/AIef9D54M/8AB3bf/F0AdpRXF/8ADR/w8/6HzwZ/4O7b/wCLo/4aP+Hn/Q+eDP8Awd23/wAXQB2lFcX/AMNH/Dz/AKHzwZ/4O7b/AOLo/wCGj/h5/wBD54M/8Hdt/wDF0Aer2P8Ax5Q/7i/yqWqfh/UrfWdBsru0nhurS6t45oJ4XDxzIygqysOCpBBBHBBq5XOaFXRv+QXB/uD+VWqq6N/yC4P9wfyq1QAUUUUAVb3RLPUpQ9xaW07gbQ0kSsQPTJHvUP8Awiml/wDQNsP/AAHT/CtCigDP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CtCigDP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8K0KKAM/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AArQooAz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8K0KKAM//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8K0KKAM//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/wrQooAz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACtCigDP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/wrQooAz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/wrQooAz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CtCigDP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAK0KKAM/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CtCigDP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CtCigDP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8K0KKAM/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AArQooAz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8K0KKAM//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8K0KKAM//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/wrQooAz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACtCigDP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/wrQooAz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/wrQooAz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CtCigDP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAK0KKAM/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CtCigDP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CtCigDP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8K0KKAM/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AArQooAz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8K0KKAM//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8K0KKAM//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/wrQooAz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACtCigDP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/wrQooAz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/wrQooAz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CtCigDP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAK0KKAM/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CtCigDP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CtCigDP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8K0KKAM/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AArQooAz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8K0KKAM//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8K0KKAM//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/wrQooAz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACtCigDP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/wrQooAz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/wrQooAz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CtCigDP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAK0KKAM/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CtCigDP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CtCigDP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8K0KKAM/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AArQooAz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8K0KKAM//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8K0KKAM//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/wrQooAz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACtCigDP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/wrQooAz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/wrQooAz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CtCigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAKujf8guD/AHB/KrVVdG/5BcH+4P5VaoAKKKKACoNS1K30bTp7y7nitbS1jaaaaVwkcSKCWZmPAAAJJPpU9Z3i4WbeFNT/ALRsTqdh9ll+02YtTdG6j2HdGIgCZCwyNmDuzjBzQBwvgP8Aa9+H3xGGrmw1q6tF0SybVLltX0i90hXshnN5CbuKIT23H+uh3x8j5uRUPhP9sv4deMfDWt6rBrV7Y2vh6KK4vk1fRb7SblYZWKwypBdQxyyxyspWN40ZZCMIWNfOUHimX9sHwH8SJk8M/ELSPG+t+EbvS/D3h/VvAGt6FZaPYAqwtWvLy0htpLudxHvCylRtVI9yxtI/aXnxQg8QeNvFnxPk+G/j/VvDfhjwdZ2C6Td+Dr2PUtR1KK9kuBFa2U0ImmMR8s+bGjJkgozbSQAes6b+2T8PdT8Dahr41TVra30q6jsbmxvPD+o2msJcSjdFCNOlgW8aSQcoqwkuMlQQK674W/FjQvjN4VXWfD91PcWfmvbyJc2c9ldWsyHDxTW86JNDIvGUkRWGRkc183/C/wCKkGp+AvEni650H4maj4u1q/t59evYPh5q2m3HhpDBJDA+mW2pWCvei1Xj93DK7GR3aPDeWN79lTwZ8R4/B89xpetwafpl94nuL+71Lxn4QuR4h8WWTxwgXEsKXFmLC4yskY3W23ZHGRbxj5SAeoeCv2r/AAJ8Q/iNN4V0nVrufVo5J4onl0m8t7G/eAlZ0tbySJba6aMgh1gkcptO4DBrc8A/Gfw78UdZ1ey0C8udSOiS+RdXUdhcLYtIGZWSK6ZBBMyMjK6xOxQjDBTXzB8LPDniHXbL4SeAIfDnirSde+F11qMmt6hfaNc2umqPsN7awzQXjoILkzSTxyAQu7KC28KRis39k74e+OvBR8MeHPBd18Q/D+uaR4Xk07xfcePLDVNT8O2+pRrbrbtaQSz28EuSJ/8AkGypEUOZDu2igD6V+JH7V3gT4TeOIfDuu6teW+pSJFLO0Gk3l3a6akrlInvLmGJ4LRXYEK1w8YbBwTima9+1p4C8NfE1PCV5rF2mqtdR2EkyaReyaba3Um3y7aa/WI2kM7+Ym2KSVZG3rhTuFfP3xk0Pxf4d0v4w+DdZ0bW/FHiv4taXZQ6Tq+geGLxdGurn7CtpKsjhrhNPjjkjMmLmfGyT5Xdsitr4o/FnRtT+P8PgHU/CnxD0bwr4f1Wy1TULnS/hprt/beLNUHlSwsLy1spLdbaJ1iaSVpNzPEFJVEYuAfQPxc+Ofhv4H6daXGv3Go79QkaK0s9M0m71a/vGUbn8q1tIpZ5Aq8sVQhRySBWJrP7X3w28P+DtE1668W6emneJAp00qkjzXQMqxHEKqZRtkdUfco2McNtNYH7Zfxnl+CHh7Rr/AEvwtrmteJNVuJNLsdW03whqHiMeHI3UNNczR2EE04jwi4RQBLII1LKuXXkfE/hmw8Qf8E/TpfgjTvGWoQ/aLXZHq/h2+0vV72YapFJczy2lzBDOpd/NlJ8pVIJZflxQB9AeOPHOk/Dbwrea3rl7Fp2l2CB5p5ATtyQqgAAszMxCqqgsxIABJArhNP8A2y/h7qPgTUfEH9qata22k3UVjdWN54f1G01eO4lAMMI06WBbxpJAQUVYSXHKg0z43+JfC/w+tvF3iO68Aa34s1nR9ItLyaPTfDM+o3GrLFPI9rbwFY2E0sc25wibmi3hyBkGvEPCVvB8Z/htr/jb7d440X4k6Vq1r4onvb74XeIYrWzlhhkggsrawuba2uNQgSGSVGEJErNI0mYyyhQD6h+GfxW0H4v+EE13QL1rrT2d4n8+2ltJ7aRDiSKaGZUlhkUjDJIqsvcCsjwN+0r4E+JUHiCfQ/E2nahaeFo0m1S7QstrbRujOsgmYCN02ox3IzAbTk15Z+yx4DvdHhk1/wCIGk32oeI/GPjG61vSZH8PtCdIP2BbZZniQy/YRJFBJgSyFgJlR3MjEV0emaHqek/Gv426mfDN1rdrfaVpX2G0ljEcOttHbXAeBJJB5bZJVTk4BcbsUAdd8Iv2kvCHxx1G+s/D15qbXmnxpPJb6lot7pUssDkhLiJLqGJpoGKkLNGGjbHDGu7r5s/Zel1Txf8AtMeI/E4X4gajot1oq2v2jxl4cbQ7jw/OLjf/AGZZIba2E9tgljL5chLIn+kSjCp9J0AFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFef8Axo/aa8KfAPU9KsdeHim5v9bSaWztNB8K6r4guZI4dgkdorC3ndEUyRgs4Ay4Gc16BXzj+2j4X0K78d6Nq+t6P8YDcWuj3dnpOr+A7jVTLDcyyxOIJotN/eAMYo2Dzg23ysJO2QD0Lxb+1/4A8C+IrDStW1TU7O8vraC7fdoV+YtLinJELX0ogKWG8ggfamiJII6gipNe/a08BeGvianhK81i7TVWuo7CSZNIvZNNtbqTb5dtNfrEbSGd/MTbFJKsjb1wp3Cvkf4qeC/iRqct2PEtt8QY/F3iHwxotq2iaB4fbUNA8c3kMO6aPVrxIJFsQkzPGSk9mChyXmUhV9S+Kvxg0fXf2g4/A2q+EPiFoXhfQ9Ws9W1GbSvhrruoWvirVf3U0JF7aWUlsLaFxE0krSBneIKdqIxcA+gPi/8AHLw38C9Is7zxFc6gv9o3H2WytdO0q71W+vZdpcrDa2scs8hCqzNsQ7VUk4AzWv4C8e6R8T/CFhr2g3seo6TqUfm29wgZd4yQQVYBlYEEFWAZSCCAQRXjnxt8aHRPi14B+IJ0Dxlf+HfDUmtaJqUdj4cvb2+tJJREsdylpFE1xLCWt2QSRRsCsysPkJaum/Y08L6n4W+BNuurWFzpd1qerarq62lymye3hu9QuLmJZF6o/lypuU8qcg8igD1SiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKR3Ea5PApar6j/AKgf71AD/tsf979DR9tj/vfoaoUVVibl/wC2x/3v0NH22P8AvfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf8Ae/Q0fbY/736GqFFFguX/ALbH/e/Q0fbY/wC9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/wB79DR9tj/vfoaoUUWC5f8Atsf979DR9tj/AL36GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/AHv0NH22P+9+hqhRRYLl/wC2x/3v0NH22P8AvfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf8Ae/Q0fbY/736GqFFFguX/ALbH/e/Q0fbY/wC9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/wB79DR9tj/vfoaoUUWC5f8Atsf979DR9tj/AL36GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/AHv0NH22P+9+hqhRRYLl/wC2x/3v0NH22P8AvfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf8Ae/Q0fbY/736GqFFFguX/ALbH/e/Q0fbY/wC9+hqhRRYLl/7bH/e/Q0fbY/736GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/wB79DR9tj/vfoaoUUWC5f8Atsf979DR9tj/AL36GqFFFguX/tsf979DR9tj/vfoaoUUWC5f+2x/3v0NH22P+9+hqhRRYLl/7bH/AHv0NH22P+9+hqhRRYLl/wC2x/3v0NH22P8AvfoaoUUWC5f+2x/3v0NAvIyfvfpVCiiwXNTNFMg/1Kf7op9SUVdG/wCQXB/uD+VWqq6N/wAguD/cH8qtUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFV9R/1A/3qsVX1H/UD/eoE9inXOfFSZo/CRXzGihnureG4dXKFYXmRX+YdBtJBPvXR1HdWsd7bvFNGksUgKujqGVwexB4NaEHn+rDSfhTaajB4Z8iyuZDaI9nGn+h2XnTeWLjYMAHkkjI3bASO9ST+JNaj1D+yI9UjeWPVYrU3xtkLtE8DSFSowm8EdQMcjKnv2Fj4T0vTNPltLbTdPt7Wf/WwxW6JHJ/vKBg/jTrDw1p2lW0UNtp9lbwwSebHHFAqLG+MbgAMA4J596AOA8MeNfEBvNKlvNQguobnWrvRpIRarHuSITbZcg53kxDOPlweFHWm6Lr/AIm1W00d212NP7W0ua+fbYx5hePZtCdsHf8ANuBJxwVzx6ImgWMQTbZWi+VM1ymIVGyVs7pBxwx3Nk9TuPrSw6JZ26RLHaWyC3jMMQWJQI0OMqvHAOBkDjgUAeX+IvjBrEfhi21SzkUyW+kWupXNtFAmzdJknzHkYEIQCFEeXzyc8A648Wa3N4n1mVb+JbHS9atrBLT7Op8yOWOAtuf72QZSRjHTnPbrbzwHoeoJEs+jaVOsEQgjElpGwjjHRBkcL7dKuLolkplItLUGeVZpSIl/eSKAFduOWAVcE8jaPSgDgLPVL/XvGfhy+ub+JoZdTvYkshCo8gRxTIvzfeJwPmznqMAd/Saz4vCelQaudQTTNPS/LFjcrboJiSCCd+M5wSOvetCgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooA0YP9Qn+6KfTIP9Qn+6KfWZoVdG/wCQXB/uD+VWqq6N/wAguD/cH8qtUAFFFFAFW9mvI5R9ngtpUxyZLhozn6BG/nUP2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFAGf9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVoUUAZ/2nVP8AnzsP/Ax//jVH2nVP+fOw/wDAx/8A41WhRQBn/adU/wCfOw/8DH/+NUfadU/587D/AMDH/wDjVaFFABVfUf8AUD/eqxVfUf8AUD/eoE9inVbWNZtfD2lT319PFa2lqhkmmkbasajqSas1ynxn0K78QeApo7KBrue3uLe7+zKQGuVimSRoxkgZIUgZOM4rQgreGvi/aeMPH66bp77rQaa95L9otZra4RhIqqSsgUhCCSDt5xwa0fD3xY0DxVrIsLG+aW4dWaEtbyxxXSr94wyMoSUDuUZsVzVjrtz4x+JUmo2eh6vHbx6DNBG+pWL2qTzGVSIiHAbt3ABByMjmuX8IR6zrHjfwTcXMXi3FhLKt5a3GjRWenaW5tnXZFtiVyuflDb3TH8WSKAPTG+Lnh9fEv9km/b7X532bd9ml+z+d/wA8vP2+V5n+xu3e1ZnxR+OGk+ANJ1lFu0Oq6bZPcbGt5ZLeF9hZFmkUbI9xxgM6k54rk/K1HR/Fn2bSNN8Q2s0+r+bc6Vc2YudHkjabc90lyY8RsVy4USZDcbO9L4ylvfDXhv4g6N/YOt6hea61zdWMllZPPHdrJCqgGQfKjKRjaxBIA2g5xQB32t/FHSfCdlZHU7iRLi8gE4htrWa5kC4G5ykSswQE8sRgdzU+s/EnRdC0Kz1Ka9ElpqOPshtonuXu8ruHlpGGd/lBPyg8CuJ8a3Gr2PiGyhSLX9OtZtKijjvdF0uK6up5gTmCV5YpFiQDBG4KMsfmGKzNK0KbS/g54I+3ab4qtLjTImDXmnxb9R0p9rL81uI38wNyGARh0OMcgA9GPxS0AeEf7d/tGP8Aszf5XmbH3+Zu2+X5eN/mbuNm3dnjFU/AfxMi8e+KtatrUq1npsduU3QSQzo8iuWWRHwykYXgqDz71x6wa7ceFtE1i+029vP7G157x40shDe3lsUkjWd4Fx+9G8MVABIXhQeK6T4b302u/ELxNqf9m6pYWd1FZrbve2rW7XAVZMsFYBhjOMMAw7gZFAHcUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAaMH+oT/AHRT6ZB/qE/3RT6zNCro3/ILg/3B/KrVVdG/5BcH+4P5VaoAKKKKACiiqPif+0v+Eb1D+xvsX9r/AGaT7D9sLC38/afL8zaC2zdjOBnGcUAXqK+T9Y+Mfj/4GxfE6T/hN5viTH4Q8KPqF/NqGm2cFtoeuHBisoWtYYd0XlkyNHKZJUXyt0n7wZ6PQH+Knhn4ha58PoPiG3inU77w7Za7Z61r2mWcMuktJePBdLGlpBFHIgiG6FZI2IdQJHcE4APo2ivmjwFr/wAQPEXgrx1aaf8AEnWdb8O6FqscFr4zfQbS61qeCOEtfpaQWloLa5ljmAjjYWrAt5ilJWQZv/sz/td6EngG3i8d/ETSY73U/EF1ovhuXxRJa6Dr2urH5e1J7BlgMd5ucgwrDG+0xkxIW20AfRFFfKPwx+OXjewk+GvjrXPF97q+h/FO4vhN4bfTrOKz0KBLO6u4DayRwrctIqWyo/nyyhy7FQmAKd+zV+299p0seJ/ixqPiDwLpfi3Rx4g0mbxLBpeleG7azXYzC3nWRrlXVZ4Q5v2jLkbo41XIoA+rKK+TPir+0R4k8bWHxK8f+A/iLFF4R+GGnWl9plnpVvYahpni3faJeyPPcPHJI0LxyIkZtZYsYZiz5AHUfFnX/iN4Z+Kvh+9tPHf+l+IdetrXRvBFnp9rNY3ukgwm8uruR4PtayxRmZ/MjnSFT5KFHZgGAPouivNv2kLfX28Pw3Nn49X4a+GNNhnvNe123htZNQgRFBjWH7XBPbKhO4uzxscBQoBOR5Z4z+I/xX0v9jnQfGMviG30PV7drdr5JtAT7ZqUUuoRRQu6u2y2Z7d90kflEh3wpj24oA+nKK434kr441ez1XTvDA0TSHkgthZazdXDTPG7TEXP+jeUV3RwjdGS7K7sAyhVJbyT4Uad4z+K/h/xppMfxl8ajQtB1eOHSfG1ppuhpqV/5cR+2QN5mnvZSQxzfIJI7ZTuR13HYSQD6Norwn9kHXfHF38MLXWdW8S6l4+0TX9Yubmy1XxC1hYX1jowjYW82yxs4YZjK0YkAKRlY7gZYlMNhfDv49+Pvi3+0frsWkXml2ng3VfBs9/4Qtbu0yLiaK6WFdRnkX94Ypi+UjUgeUqt95/lAPpOivnr9l74l+Ir74/eLfCGpeMfE3i+00bTorm4l8SeHY9Cure9Mzo62Ma2ts1zYbR8s+yVdwAE8pLBfoWgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoor5h/bG+P2qfDr4qyaVN8S4vhXYWvh3+1tBeSzs518X6kHmD2J+0RSNIqJHETDa+XcMJsq4C0AfT1FfLPxJ+J/xH1jwB4a8d6b4zbw7eeJbbSz4V8GWOn2tyniC5uIY5Z4r0zwPcBV3SHdbSxCKKMyOx5A3/jFq/xI8HfF3Q7i18d/6brviC3stH8E2Wn2s1je6UGh+2XV1I8H2tJYozO/mRzpCp8lCrswDAH0PRXkP7Q+veJNd+J/gfwH4c8T6h4LPiaPUNQvtY0+0tLm9igtEixFCLqKaBS8k6ZZ4nwqMAASGGt+yf8AELV/iX8F7a9124jvdWsdR1HSLi7SFYftps72e1ExRflVnEQYhflBY4AGBQB6RRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFV9R/1A/3qsVW1Pf5A2RPKd3RSBjr6kUCexUopmLj/nzn/wC+o/8A4qjFx/z5z/8AfUf/AMVV3JH0UzFx/wA+c/8A31H/APFUYuP+fOf/AL6j/wDiqLgPopmLj/nzn/76j/8AiqMXH/PnP/31H/8AFUXAfRTMXH/PnP8A99R//FUYuP8Anzn/AO+o/wD4qi4D6KZi4/585/8AvqP/AOKoxcf8+c//AH1H/wDFUXAfRTMXH/PnP/31H/8AFUYuP+fOf/vqP/4qi4D6KZi4/wCfOf8A76j/APiqMXH/AD5z/wDfUf8A8VRcB9FMxcf8+c//AH1H/wDFUYuP+fOf/vqP/wCKouA+imYuP+fOf/vqP/4qjFx/z5z/APfUf/xVFwH0UzFx/wA+c/8A31H/APFUYuP+fOf/AL6j/wDiqLgPopmLj/nzn/76j/8AiqMXH/PnP/31H/8AFUXAfRTMXH/PnP8A99R//FUYuP8Anzn/AO+o/wD4qi4D6KZi4/585/8AvqP/AOKoxcf8+c//AH1H/wDFUXAfRTMXH/PnP/31H/8AFUYuP+fOf/vqP/4qi4D6KZi4/wCfOf8A76j/APiqMXH/AD5z/wDfUf8A8VRcB9FMxcf8+c//AH1H/wDFUYuP+fOf/vqP/wCKouA+imYuP+fOf/vqP/4qjFx/z5z/APfUf/xVFwH0UzFx/wA+c/8A31H/APFUYuP+fOf/AL6j/wDiqLgPopmLj/nzn/76j/8AiqMXH/PnP/31H/8AFUXAfRTMXH/PnP8A99R//FUYuP8Anzn/AO+o/wD4qi4D6KZi4/585/8AvqP/AOKoxcf8+c//AH1H/wDFUXAfRTMXH/PnP/31H/8AFUYuP+fOf/vqP/4qi4D6KZi4/wCfOf8A76j/APiqMXH/AD5z/wDfUf8A8VRcB9FMxcf8+c//AH1H/wDFUYuP+fOf/vqP/wCKouA+imYuP+fOf/vqP/4qjFx/z5z/APfUf/xVFwH0UzFx/wA+c/8A31H/APFUYuP+fOf/AL6j/wDiqLgPopmLj/nzn/76j/8AiqMXH/PnP/31H/8AFUXAfRTMXH/PnP8A99R//FUYuP8Anzn/AO+o/wD4qi4D6KZi4/585/8AvqP/AOKoxcf8+c//AH1H/wDFUXAfRTMXH/PnP/31H/8AFUYuP+fOf/vqP/4qi4D6KZi4/wCfOf8A76j/APiqMXH/AD5z/wDfUf8A8VRcB9FMxcf8+c//AH1H/wDFUYuP+fOf/vqP/wCKouA+imYuP+fOf/vqP/4qjFx/z5z/APfUf/xVFwH0UzFx/wA+c/8A31H/APFUYuP+fOf/AL6j/wDiqLgPopmLj/nzn/76j/8AiqMXH/PnP/31H/8AFUXAfRTMXH/PnP8A99R//FUYuP8Anzn/AO+o/wD4qi4D6KZi4/585/8AvqP/AOKoxcf8+c//AH1H/wDFUXAfRTMXH/PnP/31H/8AFUYuP+fOf/vqP/4qi4D6KZi4/wCfOf8A76j/APiqMXH/AD5z/wDfUf8A8VRcDUg/1Cf7op9Mt8+QmQVO0ZB7U+oLKujf8guD/cH8qtVV0b/kFwf7g/lVqgAooooAKrazp7ato91apdXNi9zC8S3NuVE1uWUgOm4Mu5c5GQRkDIPSrNFAHg3wj/YSj+GfgfUfCepfE/4jeOPB2qadc6fc6JrtvoccMxuDmW4eez063unnJLkyPMxZpGZtzYIuD9iaCfwd4qsLv4j/ABKvdb8U6VHoZ8SSXVhHq2lWMbMyQWxjtFgUZd8u8LyNu+Z2IBHttFAHiXhr9jK40L4fReHrn4r/ABJ1OPS5LebQrprfQrCbw48CsifZkstNghdSrFTHcRzRkY+Wu9+DXwas/gzod9BDqWra7qWsXjajqur6o0RvNUuSiRmWQQxxwqdkcahYo0QBBhRXYUUAeQeBf2M9C8D+NbTUf7f8U6vo+jS3U+h+HdQltn0vQJLkOJmg2QLO2VlkUCeaVUV2CBRVj4S/sjaR8JPF9hqkfiLxZrdv4ftJdP8ADumapcW72fhq2l2b4bfy4Y5HBEaKGuJJnVV2qwBIPq9FAHknxX/Y/wBH+LHjPUNUm8ReLNIsPEMMFt4j0XTprZdP8SxQ5Ea3IkgeVPlOwm3khZ1AViwAFZ2q/sc6hP8AHfVvHml/GD4naBc6ybaObS7S10C4sobeEKBaxNdaZNcxwMQzMqzDLSOwIJBHtlFAHmX7S/7NX/DSWm6Bbnxt4w8Gf8I/qS6pG2hJp0q3cyA+X58V9aXUMixt86Ap8rqrA5VSLd78AD4o+CUngvxR4w8V+LfPmjmm1nUE0+31Gby7hZ0Ui1tYbcAFFX5YQSo5Jb5q9CooA4f4vfBab4u+GPEuknxn4x8O23iTTE03fo01rFLpmGctPbtJBIVlcPtYvvXaq4VTknlvBn7JVx4b+EGs+CNS+Jvj/wASaHqtgmlwJdWuiae+k2wXY0Vt/Z+n2yqGT5TuDED7pU817DRQBgax8PLXVdO0rT0nns9G01Whl0yGOFrTUbcwtD9mnSSNiYgGBwhU5RckrlT5Lof/AATK+BXhD4hT+JfD/wAMvBfha/uNEuNCYaDodnpYSKc/vJUeCJJUmK5TzFcHaxFe80UAebfCL9m2D4X+LJddv/Fni3xtrIsv7Ls7vX5LQvptlvDm3iFtbwKQWVCXkDytsXc5xXpNFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABXHfGP4PR/GrRItJvdf8AEWlaNJvTUrHS5oYF1mF12mCaQxtMiYz/AKiSJjkgsRxXY0UAeI/ET9jG58XfGFPGeh/Fj4k+Bbu30qPRrWx0a10G4srC3Q5YQLf6bcvEZCF37HG/y48jCKAX/wCxvqcnxx1Px3p/xm+KWkXuri2iuLCC18P3FoIIFUC3ja40uWeOF2DOyJMuXkdhtJGPbqKAPNfiJ+zcPiFZ6dL/AMJp4y0fxBomoXV/pmvWD2X27T1uNwktlWW2kt3g2MECywucIhLF1DV0/wAJ/hfpnwb8BWXh7STcvaWZkkaa5k8ye6lkkaWWaRsAF5JHd2IAGWOABxXR0UAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFAFXRv+QXB/uD+VWqq6N/yC4P9wfyq1QAUUUUAFFVb3RLPUpQ9xaW07gbQ0kSsQPTJHvUP/CKaX/0DbD/wHT/CgDQorP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAKANCis/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CgDQorP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CgDQorP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8KANCis/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AAoA0KKz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8KANCis//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8KANCis//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/woA0KKz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACgDQorP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/woA0KKz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/woA0KKz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CgDQorP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAKANCis/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CgDQorP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CgDQorP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8KANCis/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AAoA0KKz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8KANCis//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8KANCis//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/woA0KKz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACgDQorP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/woA0KKz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/woA0KKz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CgDQorP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAKANCis/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CgDQorP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CgDQorP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8KANCis/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AAoA0KKz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8KANCis//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8KANCis//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/woA0KKz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACgDQorP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/woA0KKz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/woA0KKz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CgDQorP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAKANCis/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CgDQorP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CgDQorP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8KANCis/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AAoA0KKz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8KANCis//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8KANCis//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/woA0KKz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACgDQorP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/woA0KKz/8AhFNL/wCgbYf+A6f4Uf8ACKaX/wBA2w/8B0/woA0KKz/+EU0v/oG2H/gOn+FH/CKaX/0DbD/wHT/CgDQorP8A+EU0v/oG2H/gOn+FH/CKaX/0DbD/AMB0/wAKANCis/8A4RTS/wDoG2H/AIDp/hR/wiml/wDQNsP/AAHT/CgDQorP/wCEU0v/AKBth/4Dp/hR/wAIppf/AEDbD/wHT/CgDQorP/4RTS/+gbYf+A6f4Uf8Ippf/QNsP/AdP8KANCis/wD4RTS/+gbYf+A6f4Uf8Ippf/QNsP8AwHT/AAoA0KKz/wDhFNL/AOgbYf8AgOn+FH/CKaX/ANA2w/8AAdP8KANCis//AIRTS/8AoG2H/gOn+FH/AAiml/8AQNsP/AdP8KANCis//hFNL/6Bth/4Dp/hR/wiml/9A2w/8B0/woA0KKz/APhFNL/6Bth/4Dp/hR/wiml/9A2w/wDAdP8ACgDQorP/AOEU0v8A6Bth/wCA6f4Uf8Ippf8A0DbD/wAB0/woA0KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCro3/ILg/wBwfyq1VXRv+QXB/uD+VWqACiiigAooqDUtSt9G06e8u54rW0tY2mmmlcJHEiglmZjwAACST6UAT0V5p4D/AGvfh98Rhq5sNaurRdEsm1S5bV9IvdIV7IZzeQm7iiE9tx/rod8fI+bkVD4T/bL+HXjHw1reqwa1e2Nr4eiiuL5NX0W+0m5WGVisMqQXUMcsscrKVjeNGWQjCFjQB6jRXl2m/tk/D3U/A2oa+NU1a2t9Kuo7G5sbzw/qNprCXEo3RQjTpYFvGkkHKKsJLjJUECuu+FvxY0L4zeFV1nw/dT3Fn5r28iXNnPZXVrMhw8U1vOiTQyLxlJEVhkZHNAHR0V514K/av8CfEP4jTeFdJ1a7n1aOSeKJ5dJvLexv3gJWdLW8kiW2umjIIdYJHKbTuAwa3PAPxn8O/FHWdXstAvLnUjokvkXV1HYXC2LSBmVkiumQQTMjIyusTsUIwwU0AdTRXnXxI/au8CfCXxxD4d13Vru31KRIpZmg0m8u7XTUlcpE95cwxPBaK7AhWuHjDYOCcUzXv2tfAXhr4mp4SvNYu01U3UdjJMmkXsmm2t1Jt8u2mv1iNpDO/mJtiklWRt64U7hQB6RRXI/Fz45+G/gfp1pca/cajv1CRorSz0zSbvVr+8ZRufyrW0ilnkCryxVCFHJIFYms/tffDbw/4O0TXrrxbp6ad4kCnTSqSPNdAyrEcQqplG2R1R9yjYxw200Aek0Vk+OPHOk/Dbwrea3rl7Fp2l2CB5p5ATtyQqgAAszMxCqqgsxIABJArkfCf7VfgTxh4I1rxDFrFxpun+G2CaqmtaXd6Nd6cWAZBLa3cUU6bwRszH8+RtzQB6JRWT4M8aWPjzwra6zYrqENjdoZIxqGn3GnThQSMvDcIkqdMjcoyMEcEGuc8DftK+BPiVB4gn0PxNp2oWnhaNJtUu0LLa20bozrIJmAjdNqMdyMwG05NAHc0Vwnwi/aS8IfHHUb6z8PXmpteafGk8lvqWi3ulSywOSEuIkuoYmmgYqQs0YaNscMa7ugAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoorgvi/+014M+BOpWdn4k1G/hur2F7oRWOkXmpNb26EB7mcW0UnkW6kgNNLsjHdhQB3tFcjrXx28LaH4m0LRm1KS81PxIiz2Fvp1nPqDvAxAW4fyEfyoMkDzpNsf+1TF/aA8GyfFqPwLHr1pP4rkSVzp8KvK0XlojuJGUFI2CSI212DEMCAaAOxorkfi/8AHLw38C9Is7zxFc6gv9o3H2WytdO0q71W+vZdpcrDa2scs8hCqzNsQ7VUk4AzWv4C8e6R8T/CFhr2g3seo6TqUfm29wgZd4yQQVYBlYEEFWAZSCCAQRQBr0UUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAVdG/5BcH+4P5Vaqro3/ILg/wBwfyq1QAUUUUAFZ3i4WbeFNT/tGxOp2H2WX7TZi1N0bqPYd0YiAJkLDI2YO7OMHNaNFAHxDB4pl/bB8B/EiZPDPxC0jxvrfhG70vw94f1bwBrehWWj2AKsLVry8tIbaS7ncR7wspUbVSPcsbSP2l58UIPEHjbxZ8T5Phv4/wBW8N+GPB1nYLpN34OvY9S1HUor2S4EVrZTQiaYxHyz5saMmSCjNtJH1VRQB8mfC/4qQan4C8SeLrnQfiZqPi7Wr+3n169g+HmrabceGkMEkMD6ZbalYK96LVeP3cMrsZHdo8N5Y3v2VPBnxHj8Hz3Gl63Bp+mX3ie4v7vUvGfhC5HiHxZZPHCBcSwpcWYsLjKyRjdbbdkcZFvGPlP0rRQB8b/Czw54h12y+EngCHw54q0nXvhddajJreoX2jXNrpqj7De2sM0F46CC5M0k8cgELuygtvCkYrN/ZO+HvjrwUfDHhzwXdfEPw/rmkeF5NO8X3Hjyw1TU/DtvqMYt1t2tIJZ7eCXJE/8AyDZUiKHMh37RX21RQB8bfGTQ/F/h3S/jD4N1nRtb8UeK/i1pdlDpOr6B4YvF0a6ufsK2kqyOGuE0+OOSMyYuZ8bJPld2yK2vij8WdG1P4/w+AdU8KfEPRvCvh/VbLVNQudL+Gmu39t4s1QeVLCwvbWykt1tonWJpJWk3M8QUlURi/wBX0UAeL/tl/GeX4IeHtGv9L8La5rXiTVbiTS7HVtN8Iah4jHhyN1DTXM0dhBNOI8IuEUASyCNSyrl15HxN4ZsPEH/BP06X4I07xlqEP2i12R6v4dvtL1e9mGpxSXM8tpcwQzqXfzZSfKVSCWX5cV9LUUAeV/G/xL4X+H1t4u8R3XgDW/Fms6PpFpeTR6b4Zn1G41ZYp5HtbeArGwmljm3OETc0W8OQMg186anaP8e/hHf681r8T7jxBN4r0jXvGMVt4N13w5cJYQEqlrpovbWCa4FuuH3QAzMyu6hHdEH2/RQB87fsv2URtoTrGkeO9S0KLxPK3gC58V2Go3esaZbHTwJJbmW8VruBS5u0R7wrIQ6qT8yg9Bpmh6npPxr+Nupnwzda3a32laV9htJYxHDrbR21wHgSSQeW2SVU5OAXG7Fe00UAfNn7L0uqeL/2mPEficL8QNR0W60VbX7R4y8ONodx4fnFxv8A7MskNtbCe2wSxl8uQlkT/SJRhU+k6KKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACvkr9unwzrN78YftcVz8S/D2n33hSTSLa+8E+HJNcl16eSZy2nXwW3uBa2+NhEwFu372TF1Fjn61ooA+EvH/AMM/FXhPX9S1KXRvijo3jnV/C2iQ+C7bwfPqMmiadqFtavG9neNbE2/kxzMSf7RJgKSZQl91fSvxC8P6rqH7Snwk1D7DczwadZ6yt/cwws0Fq8kFuFDuBhdzBguSM4OOlesUUAeC/G3xodE+LXgH4gnQPGV/4d8NSa1ompR2Phy9vb60klESx3KWkUTXEsJa3ZBJFGwKzKw+Qlq6b9jTwvqfhb4E266tYXOl3Wp6tqurraXKbJ7eG71C4uYlkXqj+XKm5TypyDyK9UooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigA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qf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKz/ALTqn/PnYf8AgY//AMao+06p/wA+dh/4GP8A/GqANCis/wC06p/z52H/AIGP/wDGqPtOqf8APnYf+Bj/APxqgDQorP8AtOqf8+dh/wCBj/8Axqj7Tqn/AD52H/gY/wD8aoA0KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigCro3/ILg/3B/KrVVdG/wCQXB/uD+VWqACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKK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J1KPzbe4QMu8ZIIKsAysCCCrAMpBBAIIrxz42+NDonxa8A/EE6B4yv8Aw74ak1rRNSjsfDl7e31pJKIljuUtIomuJYS1uyCSKNgVmVh8hLV037GnhfU/C3wJt11awudLutT1bVdXW0uU2T28N3qFxcxLIvVH8uVNynlTkHkUAeqUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAVdG/5BcH+4P5Vaqro3/ILg/3B/KrVABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAVdG/wCQXB/uD+VWqq6N/wAguD/cH8qtUAFFFFAF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UPtOqf8APnYf+Bj/APxqj7Tqn/PnYf8AgY//AMaq41wFpn2ugCt9p1T/AJ87D/wMf/41R9p1T/nzsP8AwMf/AONVZF1UizA0AUvtOqf8+dh/4GP/APGqPtOqf8+dh/4GP/8AGqvg5paACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAq6N/yC4P9wfyq1RRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFACHpUMxoooAqTGod1FFAChuasQmiigC1Ef51LRRQB//9k=", - "description": null, + "image": "data:image/png;base64,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", + "description": "Allows users to create and display custom statistic metric data in real-time.", "descriptor": { "type": "timeseries", "sizeX": 8, @@ -18,6 +18,6 @@ "settingsDirective": "tb-flot-line-widget-settings", "dataKeySettingsDirective": "tb-flot-line-key-settings", "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"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;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Gateway statistics\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"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;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"shadowSize\":4,\"fontColor\":\"#545454\",\"fontSize\":10,\"xaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"showLabels\":true,\"color\":\"#545454\"},\"grid\":{\"color\":\"#545454\",\"tickColor\":\"#DDDDDD\",\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1},\"legend\":{\"show\":true,\"position\":\"nw\",\"backgroundColor\":\"#f0f0f0\",\"backgroundOpacity\":0.85,\"labelBoxBorderColor\":\"rgba(1, 1, 1, 0.45)\"},\"decimals\":1,\"stack\":false,\"tooltipIndividual\":false},\"title\":\"Gateway custom statistics \",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null}" } -} \ No newline at end of file +} diff --git a/application/src/main/data/json/system/widget_types/service_rpc.json b/application/src/main/data/json/system/widget_types/service_rpc.json index aa6730697b..7397256e49 100644 --- a/application/src/main/data/json/system/widget_types/service_rpc.json +++ b/application/src/main/data/json/system/widget_types/service_rpc.json @@ -2,8 +2,8 @@ "fqn": "gateway_widgets.service_rpc", "name": "Service RPC", "deprecated": false, - "image": "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAkACQAAD/4QAiRXhpZgAATU0AKgAAAAgAAQESAAMAAAABAAEAAAAAAAD/2wBDAAIBAQIBAQICAgICAgICAwUDAwMDAwYEBAMFBwYHBwcGBwcICQsJCAgKCAcHCg0KCgsMDAwMBwkODw0MDgsMDAz/2wBDAQICAgMDAwYDAwYMCAcIDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAz/wAARCAJNBKMDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD9/KKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAoooo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Nm8SeLPidri6Tp+lWdwiXFvCEZ5r2RTkiGJVyxwBzjOa9moAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK4Oy/ap+GGp+L18PW3xI8B3GvtcmyXTI/EFo9404baYhEJN/mBgRtxnIxiu8r4N/YQ/4IveDfhB8UvGXxI+JXg7w7qnxKufiJqvijw9rVpqNy8lnZz3BltgyhkTeu5sqVYZJGSKAPsn4j/HPwT8HHtV8XeMPC3hVr8MbYaxq0FibgLjds8113YyM4zjIrV8HeNtF+Inh231jw/q+l67pN5kwXun3SXVvNglTtkQlWwQQcHggivJ/2yv2APhX+3HoVovxF8G2Hiy+0K3uF0drq6uIVtJJVGT+6dQclU+8DjH1rH/4JX/sx+JP2N/2DfAHw38XNpsniLwzbTQ3jWE5mtyWnkkGx2VSRtYdQKAPoSiiigCvqulWuvaZcWN9bW95Z3kbQz288YkimRhhlZTkMpBIIPBFfL6/8ESP2V18bjXv+FN+H/tIuPtQs/tV3/ZQlznd/Z/nfZM/9sunHSvqiigDmfiH8GfCfxa+Gt34N8TeHNG1vwrfW4tZtJu7RJLR4gAFXYRgbcDGMFSARjAryv8AZw/4JifAj9krxq3iTwF8O9O0nXhG0MOoXN5dalcWcbfeSB7qWUwIem2LaMcYxxXvVFAHF/Dz9nrwf8KfiL408WaBo/2DxB8Q7uC+8QXX2qeX+0JoYVgjbY7ske2NVXEaqDjJBPNM+Ov7OPgn9pjQNK0vx14ftfEOn6Jq1trllDNJJGILy3bfDLlGUnaeqnKsOGBHFdvRQByPx1+BfhX9pb4Ta14F8baX/bXhXxFB9m1Cy+0zW32iPcGx5kLpIvKg5VgeKh+Lv7Ovgf4+fCmTwP408M6X4k8KzRpGdPvo/NRdgwjK2dyuuOHUhh1BrtKKAPHf2X/+Cf8A8Hv2M7rULr4b+B7DQNQ1RRHd6hJc3GoX80YORGbm5kkm8sHkIH2j0rL/AGkv+CZnwL/a48bweJvH3w907VvEVvEIP7Utry6028niHSOWW1lieZB/dkLL2xXu1FAHN/CT4PeFvgL4A0/wr4L0DS/DPh3Sk8u10/T7dYYIR1JwOrE8ljkknJJNZnxT/Zy8GfGvxn4K8QeJtG/tLWPh3qbax4euPtc8P9n3TRmMybY3VZPlJG2QMvfGea7eigDi/wBoH9nfwb+1N8L73wZ480SPX/DmoSRTS2zTy27rJE4kjkSWFkkjdXUEMjKwI61Dffs2+C9T+MPhfx9caRJP4u8GaXcaNo+ovfXDNa2k+zzoynmbJC3lp88is4xwRk57qigArg/2h/2YPh9+1l4Dbwz8RvCWj+LtF8wTJb38O4wSDgSROCHjfGRuRlbBPNd5RQB4j+y//wAE4vgn+xprV3qnw58A6boes30flTapPc3Gpai8f/PP7TdSSzBOnyhwOBxwK9uoooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAK+Df2EP8AgtD4N+L/AMUvGXw3+JXjHw7pfxKtviJqvhfw9otpp1ykl5ZwXBitizBXTe21ssWUZBOAK+8q4Oy/ZX+GGmeL18Q23w38B2+vrcm9XU4/D9ol4s5bcZRKI9/mFiTuznJzmgDj/wBsr9v/AOFf7DmhWjfEXxlYeE77Xbe4bR1urW4mW7kiUZH7pGAwWT7xGc/Wsf8A4JX/ALTniT9sf9g3wB8SPFy6bH4i8TW0014thAYbcFZ5IxsRmYgbVHUmvW/iP8DfBPxje1bxd4P8LeKmsAwtjrGk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in5Uf8I5af8APFPyq9RQBR/4Ry0/54p+VH/COWn/ADxT8qvUUAUf+EctP+eKflTo9DtYjlYkH4VcooAakaxj5RTqKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAory9/jd4tsz5c/w51CSVTgtb6lC0be4LBT+YpP+F7+KP+ib61/4H2/+NAHqNFeXf8L38Uf9E31r/wAD7f8Axo/4Xv4o/wCib61/4H2/+NAHqNFeXf8AC9/FH/RN9a/8D7f/ABo/4Xv4o/6JvrX/AIH2/wDjQB6jRXl3/C9/FH/RN9a/8D7f/Gj/AIXv4o/6JvrX/gfb/wCNAHqNFeXf8L38Uf8ARN9a/wDA+3/xo/4Xv4o/6JvrX/gfb/40Aeo0V5d/wvfxR/0TfWv/AAPt/wDGj/he/ij/AKJvrX/gfb/40Aeo0V5d/wAL38Uf9E31r/wPt/8AGj/he/ij/om+tf8Agfb/AONAHqNFeXf8L38Uf9E31r/wPt/8aP8Ahe/ij/om+tf+B9v/AI0Aeo0V5d/wvfxR/wBE31r/AMD7f/Gj/he/ij/om+tf+B9v/jQB6jRXl3/C9/FH/RN9a/8AA+3/AMaP+F7+KP8Aom+tf+B9v/jQB6jRXl3/AAvfxR/0TfWv/A+3/wAaP+F7+KP+ib61/wCB9v8A40Aeo0V5d/wvfxR/0TfWv/A+3/xo/wCF7+KP+ib61/4H2/8AjQB6jRXl3/C9/FH/AETfWv8AwPt/8aP+F7+KP+ib61/4H2/+NAHqNFeXf8L38Uf9E31r/wAD7f8Axo/4Xv4o/wCib61/4H2/+NAHqNFeXf8AC9/F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CH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/RWB/wsCH/nxvf++of/jlH/CwIf8Anxvf++of/jlAG/RWB/wsCH/nxvf++of/AI5R/wALAh/58b3/AL6h/wDjlAG/VPU9Gj1D5vuSf3h3+tZn/CwIf+fG9/76h/8AjlH/AAsCH/nxvf8AvqH/AOOUAQXGi3Nu3+rZh6r82ahFnMzYEUhPptNXf+FgQ/8APje/99Q//HKP+FgQ/wDPje/99Q//ABygBln4fnuG+dfKX1PX8q3LGwjsItsa/Unqaxv+FgQ/8+N7/wB9Q/8Axyj/AIWBD/z43v8A31D/APHKAN+is3w54nt/E8d0YFmjazn+zyrIBlW2I/YkH5XU8HvWlQAUUUUAFFFFAHlf7Q//ACMvh3/r2vf/AEK2rh67j9of/kZfDv8A17Xv/oVtXD0AFFFFAGb4s8Y6T4C0C41bXNU0/RtLs13z3l9cJbwQr6s7kKB9TXH/AAC/as+H/wC1HBrU3gHxJb+JIPD10tnfTQQTJFHKQWAV3RVkBAzuQsvvW78Ufg54V+NmiWum+LtB0zxFp1ndx30VrfwiaETJnaxQ8NjJ4II56V85f8E7bWKx/aX/AGoYYY44YYvG0KJGihVRRbDAAHAA9KAPrKiiigDovAP/AC9/8A/9mrmfgp/yP/jv/sID/wBGT103gH/l7/4B/wCzVzPwU/5H/wAd/wDYQH/oyegD0iiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDW+D/XxJ/2FR/6SW1dlXG/B/r4k/7Co/8ASS2rsqACiiigAooooA8r/aH/AORl8O/9e17/AOhW1cPXpPxh0Vdd8Z6DC0jRhbK9fIH+3aj+tYf/AArmH/n5l/75FAHJUV1v/CuYf+fmX/vkUf8ACuYf+fmX/vkUAeOfH7/hY3/CvZP+FW/8IT/wlf2iPZ/wlX2r+z/J58zP2f8Aeb+mO3XNfMf7Ln7Nv7UPwR+OnijxFql18BLjR/iLr8OseJUtJdWe5gVVCOtmGRVU7M4EpbnqcV9//wDCuYf+fmX/AL5FH/CuYf8An5l/75FAHJUV1v8AwrmH/n5l/wC+RR/wrmH/AJ+Zf++RQBU8A/8AL3/wD/2auZ+Cn/I/+O/+wgP/AEZPXp3gr4eIv2rZ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", - "description": null, + "image": "data:image/png;base64,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", + "description": "Allow users to send RPC requests through the gateway.", "descriptor": { "type": "rpc", "sizeX": 8.5, @@ -17,4 +17,4 @@ "settingsDirective": "tb-gateway-service-rpc-settings", "defaultConfig": "{\"targetDeviceAliases\":[],\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"isConnector\":false},\"title\":\"Service RPC\"}" } -} \ No newline at end of file +} 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 2428f5cdc3..428dc575d4 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 @@ -17,8 +17,6 @@ import { Inject, Injectable, Type } from '@angular/core'; import { Observable } from 'rxjs'; import { MatDialog, MatDialogConfig } 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 { mergeMap, tap } from 'rxjs/operators'; @@ -28,7 +26,11 @@ import { CustomDialogContainerData } from '@home/components/widget/dialog/custom-dialog-container.component'; import { SHARED_MODULE_TOKEN } from '@shared/components/tokens'; -import { HOME_COMPONENTS_MODULE_TOKEN, SHARED_HOME_COMPONENTS_MODULE_TOKEN } from '@home/components/tokens'; +import { + HOME_COMPONENTS_MODULE_TOKEN, + SHARED_HOME_COMPONENTS_MODULE_TOKEN, + WIDGET_COMPONENTS_MODULE_TOKEN +} from '@home/components/tokens'; @Injectable() export class CustomDialogService { @@ -36,12 +38,11 @@ export class CustomDialogService { private customModules: Array>; constructor( - 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, @Inject(HOME_COMPONENTS_MODULE_TOKEN) private homeComponentsModule: Type, + @Inject(WIDGET_COMPONENTS_MODULE_TOKEN) private widgetComponentsModule: Type, public dialog: MatDialog ) { } @@ -52,7 +53,8 @@ export class CustomDialogService { customDialog(template: string, controller: (instance: CustomDialogComponent) => void, data?: any, config?: MatDialogConfig): Observable { - const modules = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule]; + const modules = [this.sharedModule, CommonModule, this.sharedHomeComponentsModule, this.homeComponentsModule, + this.widgetComponentsModule]; if (Array.isArray(this.customModules)) { modules.push(...this.customModules); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html index f1a0430fcf..2d7a604852 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/device-gateway-command.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+
{{ 'gateway.docker-label' | translate }}
@@ -60,7 +60,8 @@
-
+
+
device.connectivity.execute-following-command
- +

gateway.gateway-configuration

- -
- +
@@ -713,7 +706,7 @@
-
+
- - - - {{ 'gateway.connectors-table-enabled' | translate }} - - - - - - - - {{ 'gateway.connectors-table-name' | translate }} - - {{ attribute.key }} - - - - - {{ 'gateway.connectors-table-type' | translate }} - - - {{ returnType(attribute) }} - - - - - {{ 'gateway.configuration' | translate }} - - -
- {{ isConnectorSynced(attribute) ? 'sync' : 'out of sync' }} -
-
-
- - - {{ 'gateway.connectors-table-status' | translate }} - - - - - - - - {{ 'gateway.connectors-table-actions' | translate }} - - -
- - - -
-
- - +
+
+ + + {{ 'gateway.connectors-table-enabled' | translate }} + + + + + + + + {{ 'gateway.connectors-table-name' | translate }} + + {{ attribute.key }} + + + + + {{ 'gateway.connectors-table-type' | translate }} + + + {{ returnType(attribute) }} + + + + + {{ 'gateway.configuration' | translate }} + + +
+ {{ isConnectorSynced(attribute) ? 'sync' : 'out of sync' }} +
+
+
+ + + {{ 'gateway.connectors-table-status' | translate }} + + + + + + + + {{ 'gateway.connectors-table-actions' | translate }} + + +
- -
-
-
- - -
+
+
+ + + + + + +
+ + + + + +
-
- - {{ 'gateway.connectors-table-name' | translate }} - - - - {{ 'gateway.connectors-table-type' | translate }} - - {{ type.value }} - - - - {{ 'gateway.connectors-table-key' | translate }} - - - - {{ 'gateway.connectors-table-class' | translate }} - - - - gateway.remote-logging-level - - {{ logLevel }} - - +
+
+ + {{ 'gateway.connectors-table-name' | translate }} + + + + {{ 'gateway.connectors-table-type' | translate }} + + {{ type.value }} + + + + {{ 'gateway.connectors-table-key' | translate }} + + + + {{ 'gateway.connectors-table-class' | translate }} + + + + gateway.remote-logging-level + + {{ logLevel }} + + +
-
+
-
+
- - - -
-
- -
-
- -
+ +

{{ dialogTitle }}

+ + +
+
+
+
+ + + + + Ubuntu + + +
+
+ +
+
+
+
+ + + + CentOS + + +
+
+ +
+
+
+
+ + + + Docker + + +
+
+ +
+
+
+
+
+
+
+
+ {{ 'action.dont-show-again' | translate}} + + +
+ +
+ + + {{ 'edge.loading-edge-instructions' | translate }} + +
+
diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss new file mode 100644 index 0000000000..d69eeb6c23 --- /dev/null +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -0,0 +1,129 @@ +/** + * Copyright © 2016-2023 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 { + height: 100%; + max-height: 100vh; + display: grid; + grid-template-rows: min-content minmax(auto, 1fr) min-content; + + .tb-loader { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 16px; + height: 300px; + max-height: 100%; + + .label { + margin-bottom: 0; + text-align: center; + } + } + + .tb-font-14 { + font-size: 14px; + } + + .tb-flex-1 { + flex: 1; + } + + @media #{$mat-sm} { + width: 470px; + } + + @media #{$mat-gt-sm} { + width: 720px; + } +} + +:host-context(.mat-mdc-dialog-container) { + .tb-dialog-actions { + display: flex; + gap: 8px; + padding: 8px 16px; + } + + .mat-mdc-dialog-content { + max-height: 80vh; + padding: 16px; + } +} + +:host ::ng-deep { + .tb-markdown-view { + .tb-command-code { + .code-wrapper { + padding: 0; + pre[class*=language-] { + margin: 0; + background: #F3F6FA; + border-color: #305680; + padding-right: 38px; + overflow: scroll; + padding-bottom: 4px; + + &::-webkit-scrollbar { + width: 4px; + height: 4px; + } + } + } + button.clipboard-btn { + right: -2px; + p { + color: #305680; + } + p, div { + background-color: #F3F6FA; + } + div { + img { + display: none; + } + &:after { + content: ""; + position: initial; + display: block; + width: 18px; + height: 18px; + background: #305680; + mask-image: url(/assets/copy-code-icon.svg); + mask-repeat: no-repeat; + } + } + } + } + } + .mdc-button__label > span { + .mat-icon { + vertical-align: text-bottom; + box-sizing: initial; + } + } + + .tabs-icon { + margin-right: 8px; + } + + .tb-form-panel.tb-tab-body { + padding: 16px 0 0; + } +} diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts index a4dfe4345b..51d7e42238 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts @@ -14,33 +14,83 @@ /// limitations under the License. /// -import { Component, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from "@angular/material/dialog"; -import { DialogComponent } from "@shared/components/dialog.component"; -import { Store } from "@ngrx/store"; -import { AppState } from "@core/core.state"; -import { Router } from "@angular/router"; - -export interface EdgeInstructionsData { - instructions: string; +import { Component, Inject, OnDestroy, 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 { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { ActionPreferencesPutUserSettings } from '@core/auth/auth.actions'; +import { EdgeInfo, EdgeInstructionsMethod } from '@shared/models/edge.models'; +import { EdgeService } from '@core/http/edge.service'; + +export interface EdgeInstructionsDialogData { + edge: EdgeInfo; + afterAdd: boolean; } @Component({ - selector: 'tb-edge-instructions', - templateUrl: './edge-instructions-dialog.component.html' + selector: 'tb-edge-installation-dialog', + templateUrl: './edge-instructions-dialog.component.html', + styleUrls: ['./edge-instructions-dialog.component.scss'] }) -export class EdgeInstructionsDialogComponent extends DialogComponent { +export class EdgeInstructionsDialogComponent extends DialogComponent implements OnInit, OnDestroy { + + dialogTitle: string; + showDontShowAgain: boolean; - instructions: string = this.data.instructions; + loadedInstructions = false; + notShowAgain = false; + tabIndex = 0; + instructionsMethod = EdgeInstructionsMethod; + contentData: any = {}; constructor(protected store: Store, protected router: Router, - public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: EdgeInstructionsData) { + @Inject(MAT_DIALOG_DATA) private data: EdgeInstructionsDialogData, + public dialogRef: MatDialogRef, + private edgeService: EdgeService) { super(store, router, dialogRef); + + if (this.data.afterAdd) { + this.dialogTitle = 'edge.install-connect-instructions-edge-created'; + this.showDontShowAgain = true; + } else { + this.dialogTitle = 'edge.install-connect-instructions'; + this.showDontShowAgain = false; + } + } + + ngOnInit() { + this.getInstructions(this.instructionsMethod[this.tabIndex]); + } + + ngOnDestroy() { + super.ngOnDestroy(); + } + + close(): void { + if (this.notShowAgain && this.showDontShowAgain) { + this.store.dispatch(new ActionPreferencesPutUserSettings({notDisplayInstructionsAfterAddEdge: true})); + this.dialogRef.close(null); + } else { + this.dialogRef.close(null); + } + } + + selectedTabChange(index: number) { + this.getInstructions(this.instructionsMethod[index]); } - cancel(): void { - this.dialogRef.close(null); + getInstructions(method: string) { + if (!this.contentData[method]) { + this.loadedInstructions = false; + this.edgeService.getEdgeDockerInstallInstructions(this.data.edge.id.id, method).subscribe( + res => { + this.contentData[method] = res.installInstructions; + this.loadedInstructions = true; + } + ); + } } } diff --git a/ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts index 1acaff3841..6a80388b52 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edges-table-config.resolver.ts @@ -29,10 +29,10 @@ import { import { TranslateService } from '@ngx-translate/core'; import { DatePipe } from '@angular/common'; import { EntityType, entityTypeResources, entityTypeTranslations } from '@shared/models/entity-type.models'; -import { EntityAction } from '@home/models/entity/entity-component.models'; +import { AddEntityDialogData, EntityAction } from '@home/models/entity/entity-component.models'; import { forkJoin, Observable, of } from 'rxjs'; import { select, Store } from '@ngrx/store'; -import { selectAuthUser } from '@core/auth/auth.selectors'; +import { selectAuthUser, selectUserSettingsProperty } from '@core/auth/auth.selectors'; import { map, mergeMap, take, tap } from 'rxjs/operators'; import { AppState } from '@core/core.state'; import { Authority } from '@app/shared/models/authority.enum'; @@ -51,7 +51,7 @@ import { AddEntitiesToCustomerDialogData } from '../../dialogs/add-entities-to-customer-dialog.component'; import { HomeDialogsService } from '@home/dialogs/home-dialogs.service'; -import { Edge, EdgeInfo, EdgeInstallInstructions } from '@shared/models/edge.models'; +import { Edge, EdgeInfo } from '@shared/models/edge.models'; import { EdgeService } from '@core/http/edge.service'; import { EdgeComponent } from '@home/pages/edge/edge.component'; import { EdgeTableHeaderComponent } from '@home/pages/edge/edge-table-header.component'; @@ -59,9 +59,10 @@ import { EdgeId } from '@shared/models/id/edge-id'; import { EdgeTabsComponent } from '@home/pages/edge/edge-tabs.component'; import { ActionNotificationShow } from '@core/notification/notification.actions'; import { - EdgeInstructionsData, - EdgeInstructionsDialogComponent -} from "@home/pages/edge/edge-instructions-dialog.component"; + EdgeInstructionsDialogComponent, + EdgeInstructionsDialogData +} from '@home/pages/edge/edge-instructions-dialog.component'; +import { AddEntityDialogComponent } from '@home/components/entity/add-entity-dialog.component'; @Injectable() export class EdgesTableConfigResolver implements Resolve> { @@ -140,6 +141,7 @@ export class EdgesTableConfigResolver implements Resolve this.config.componentsData.edgeScope === 'tenant'; + this.config.addEntity = () => { this.addEdge(); return of(null); }; return this.config; }) ); @@ -530,21 +532,50 @@ export class EdgesTableConfigResolver implements Resolve, + EdgeInfo>(AddEntityDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + entitiesTableConfig: this.config + } + }).afterClosed().subscribe( + (entity) => { + if (entity) { + this.store.pipe(select(selectUserSettingsProperty('notDisplayInstructionsAfterAddEdge'))).pipe( + take(1) + ).subscribe((settings: boolean) => { + if (!settings) { + this.openInstructions(null, entity, true); + } else { + this.config.updateData(); + this.config.entityAdded(entity); + } + }); + } + } + ); + } + + openInstructions($event, edge: EdgeInfo, afterAdd = false) { if ($event) { $event.stopPropagation(); } - this.edgeService.getEdgeDockerInstallInstructions(edge.id.id).subscribe( - (edgeInstructionsTemplate: EdgeInstallInstructions) => { - this.dialog.open(EdgeInstructionsDialogComponent, { - disableClose: false, - panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], - data: { - instructions: edgeInstructionsTemplate.dockerInstallInstructions - } - }); + this.dialog.open + (EdgeInstructionsDialogComponent, { + disableClose: true, + panelClass: ['tb-dialog', 'tb-fullscreen-dialog'], + data: { + edge, + afterAdd } - ) + }).afterClosed().subscribe(() => { + if (afterAdd) { + this.config.updateData(); + } + } + ); } onEdgeAction(action: EntityAction, config: EntityTableConfig): boolean { diff --git a/ui-ngx/src/app/shared/models/edge.models.ts b/ui-ngx/src/app/shared/models/edge.models.ts index 1acfa2ca28..7b5a6ddb3d 100644 --- a/ui-ngx/src/app/shared/models/edge.models.ts +++ b/ui-ngx/src/app/shared/models/edge.models.ts @@ -179,5 +179,11 @@ export interface EdgeEvent extends BaseData { } export interface EdgeInstallInstructions { - dockerInstallInstructions: string; + installInstructions: string; +} + +export enum EdgeInstructionsMethod { + ubuntu, + centos, + docker } diff --git a/ui-ngx/src/app/shared/models/user-settings.models.ts b/ui-ngx/src/app/shared/models/user-settings.models.ts index ac0bd95c29..bd64e0241b 100644 --- a/ui-ngx/src/app/shared/models/user-settings.models.ts +++ b/ui-ngx/src/app/shared/models/user-settings.models.ts @@ -17,6 +17,7 @@ export interface UserSettings { openedMenuSections?: string[]; notDisplayConnectivityAfterAddDevice?: boolean; + notDisplayInstructionsAfterAddEdge?: boolean; } export const initialUserSettings: UserSettings = { 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 672ed9b1b2..6e9c0375c9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1962,6 +1962,8 @@ "make-private-edge-text": "After the confirmation the edge and all its data will be made private and won't be accessible by others.", "import": "Import edge", "install-connect-instructions": "Install & Connect Instructions", + "install-connect-instructions-edge-created": "Edge created! Check Install & Connect Instructions", + "loading-edge-instructions": "Loading edge instructions...", "label": "Label", "load-entity-error": "Failed to load data. Entity has been deleted.", "assign-new-edge": "Assign new edge", From 64f1b056f29f0c33c1e3bf9ea57157a53fc755a3 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Wed, 13 Sep 2023 16:09:25 +0300 Subject: [PATCH 035/267] Edge instructions style updates --- .../edge-instructions-dialog.component.html | 22 +++++++++---------- .../edge-instructions-dialog.component.scss | 8 +++++-- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html index cf834e203e..e01e2ec965 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.html @@ -30,13 +30,13 @@ - + Ubuntu -
-
- +
+
+
@@ -44,12 +44,12 @@ - CentOS + CentOS/RHEL -
-
- +
+
+
@@ -60,9 +60,9 @@ Docker -
-
- +
+
+
diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index d69eeb6c23..1524150330 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -46,11 +46,11 @@ } @media #{$mat-sm} { - width: 470px; + width: 705px; } @media #{$mat-gt-sm} { - width: 720px; + width: 1080px; } } @@ -111,6 +111,10 @@ } } } + > p, h1, h2, h3, h4, h5, div { + padding-left: 16px !important; + padding-right: 16px !important; + } } .mdc-button__label > span { .mat-icon { From 071d12527774a9116a376d65244ba1198ad79964 Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Wed, 13 Sep 2023 16:16:55 +0300 Subject: [PATCH 036/267] PROD-2416: global table cell background change --- 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 a584985924..47a7bbbac2 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -699,7 +699,7 @@ mat-label { } .mat-mdc-cell { - background: inherit; + background-color: transparent; color: inherit; font-size: inherit; font-family: inherit; From cb546e7bd52022a479cd1fd65a0ffe92b1780efc Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 13 Sep 2023 13:42:22 +0300 Subject: [PATCH 037/267] UI: Fixed form style and enhancement hint tooltip component --- .../gateway-configuration.component.html | 30 +++++++++---------- .../gateway/gateway-connectors.component.html | 2 +- .../components/file-input.component.html | 13 ++++---- .../components/file-input.component.scss | 4 +-- .../hint-tooltip-icon.component.html | 5 ++-- .../hint-tooltip-icon.component.scss | 4 ++- .../components/hint-tooltip-icon.component.ts | 3 +- ui-ngx/src/form.scss | 2 +- 8 files changed, 31 insertions(+), 32 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html index 59b63d0051..9b0b8837e2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html @@ -34,7 +34,7 @@ {{ 'gateway.remote-shell' | translate }}
-
+
gateway.thingsboard-host @@ -84,7 +84,7 @@ matTooltip="{{ 'gateway.hints.token' | translate }}">info_outlined -
security.clientId @@ -181,7 +181,7 @@ class="first-capital">{{ localLogsConfigTranslateMap.get(logConfig) }} -
+
gateway.logs.level @@ -196,8 +196,8 @@
-
-
+
+
gateway.logs.saving-period @@ -250,7 +250,7 @@
{{ 'gateway.hints.' + gatewayConfigGroup.get('storage.type').value | translate }}
-
+
gateway.storage-read-record-count @@ -285,7 +285,7 @@
-
+
gateway.storage-data-folder-path @@ -315,7 +315,7 @@
-
+
gateway.storage-max-read-record-count @@ -351,7 +351,7 @@
-
+
gateway.storage-path @@ -413,7 +413,7 @@
-
+
gateway.server-port @@ -450,7 +450,7 @@
-
+
gateway.grpc-keep-alive @@ -484,7 +484,7 @@
-
+
gateway.grpc-max-pings-without-data @@ -552,7 +552,7 @@
-
+
gateway.statistics.attribute-name @@ -619,7 +619,7 @@ {{ 'gateway.checking-device-activity' | translate }}
-
gateway.inactivity-timeout-seconds @@ -655,7 +655,7 @@
gateway.advanced
-
+
gateway.min-pack-send-delay diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html index 4debb6a62f..0c21261091 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-connectors.component.html @@ -143,7 +143,7 @@
-
+
{{ 'gateway.connectors-table-name' | translate }} diff --git a/ui-ngx/src/app/shared/components/file-input.component.html b/ui-ngx/src/app/shared/components/file-input.component.html index c0c004d02c..398f78451d 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.html +++ b/ui-ngx/src/app/shared/components/file-input.component.html @@ -16,14 +16,11 @@ -->
- - - - - - +
diff --git a/ui-ngx/src/app/shared/components/file-input.component.scss b/ui-ngx/src/app/shared/components/file-input.component.scss index 45ed704336..e172abd6e9 100644 --- a/ui-ngx/src/app/shared/components/file-input.component.scss +++ b/ui-ngx/src/app/shared/components/file-input.component.scss @@ -22,10 +22,8 @@ $previewSize: 100px !default; .tb-container { margin-top: 0; label.tb-title { + display: flex; padding-bottom: 8px; - &:not(.pointer-event) { - display: block; - } } } diff --git a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.html b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.html index 7fff74a55e..63feb714d6 100644 --- a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.html +++ b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.html @@ -17,5 +17,6 @@ --> {{ hintIcon }} + *ngIf="tooltipText" + matTooltip="{{ tooltipText }}" + [matTooltipPosition]="tooltipPosition">{{ hintIcon }} diff --git a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.scss b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.scss index 4febf04f15..80e36d117d 100644 --- a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.scss +++ b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.scss @@ -13,12 +13,14 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -:host { +:host(.tb-hint-tooltip) { display: flex; flex-direction: row; align-items: center; gap: 8px; +} +:host { .tb-hint-tooltip-icon { color: #E0E0E0; overflow: visible; diff --git a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.ts b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.ts index 2d6ee282c1..dde6dc98e8 100644 --- a/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.ts +++ b/ui-ngx/src/app/shared/components/hint-tooltip-icon.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Input } from '@angular/core'; +import { Component, HostBinding, Input } from '@angular/core'; import { TooltipPosition } from '@angular/material/tooltip'; @Component({ @@ -24,6 +24,7 @@ import { TooltipPosition } from '@angular/material/tooltip'; }) export class HintTooltipIconComponent { + @HostBinding('class.tb-hint-tooltip') @Input('tb-hint-tooltip-icon') tooltipText: string; @Input() diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 63f126f405..77a31eeb2e 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -221,7 +221,7 @@ } } - .tb-form-row:not(.tb-not-inline-field) .mat-mdc-form-field, .mat-mdc-form-field.tb-inline-field { + .tb-form-row:not(.tb-standard-fields) .mat-mdc-form-field:not(.tb-not-inline-field), .mat-mdc-form-field.tb-inline-field { &.mat-form-field-appearance-fill { .mdc-text-field--filled:not(.mdc-text-field--disabled) { &:before { From 3f2a3e35ff2ad2af9a6b20ee7dc242f0dcf8f770 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 12 Sep 2023 09:58:56 +0300 Subject: [PATCH 038/267] Fixes for partition recalculation with isolated queues --- .../DefaultTbRuleEngineConsumerService.java | 1 + .../discovery/HashPartitionServiceTest.java | 175 +++++++++++++++--- .../queue/discovery/HashPartitionService.java | 24 ++- 3 files changed, 165 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 670dbcaa6d..f13a4ef39c 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -501,6 +501,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } } + partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { diff --git a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java index 7bd9ec576f..5e800d52a5 100644 --- a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java @@ -23,6 +23,7 @@ import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.Mockito; import org.mockito.junit.MockitoJUnitRunner; import org.springframework.context.ApplicationEventPublisher; import org.springframework.test.util.ReflectionTestUtils; @@ -35,7 +36,9 @@ import org.thingsboard.server.common.data.id.UUIDBased; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ServiceInfo; +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import java.text.SimpleDateFormat; import java.util.ArrayList; @@ -49,12 +52,17 @@ import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.TimeUnit; +import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @Slf4j @@ -78,15 +86,7 @@ public class HashPartitionServiceTest { applicationEventPublisher = mock(ApplicationEventPublisher.class); routingInfoService = mock(TenantRoutingInfoService.class); queueRoutingInfoService = mock(QueueRoutingInfoService.class); - clusterRoutingService = new HashPartitionService(discoveryService, - routingInfoService, - applicationEventPublisher, - queueRoutingInfoService); - ReflectionTestUtils.setField(clusterRoutingService, "coreTopic", "tb.core"); - ReflectionTestUtils.setField(clusterRoutingService, "corePartitions", 10); - ReflectionTestUtils.setField(clusterRoutingService, "vcTopic", "tb.vc"); - ReflectionTestUtils.setField(clusterRoutingService, "vcPartitions", 10); - ReflectionTestUtils.setField(clusterRoutingService, "hashFunctionName", hashFunctionName); + clusterRoutingService = createPartitionService(); ServiceInfo currentServer = ServiceInfo.newBuilder() .setServiceId("tb-core-0") .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) @@ -101,8 +101,6 @@ public class HashPartitionServiceTest { .build()); } - clusterRoutingService.init(); - clusterRoutingService.partitionsInit(); clusterRoutingService.recalculatePartitions(currentServer, otherServers); } @@ -194,25 +192,12 @@ public class HashPartitionServiceTest { } List queues = new ArrayList<>(); - Queue systemQueue = new Queue(); - systemQueue.setTenantId(TenantId.SYS_TENANT_ID); - systemQueue.setName("Main"); - systemQueue.setTopic(DataConstants.MAIN_QUEUE_TOPIC); - systemQueue.setPartitions(10); - systemQueue.setId(new QueueId(UUID.randomUUID())); - queues.add(systemQueue); + queues.add(createQueue(TenantId.SYS_TENANT_ID, 10)); tenants.forEach((tenantId, profileId) -> { - Queue isolatedQueue = new Queue(); - isolatedQueue.setTenantId(tenantId); - isolatedQueue.setName("Main"); - isolatedQueue.setTopic(DataConstants.MAIN_QUEUE_TOPIC); - isolatedQueue.setPartitions(2); - isolatedQueue.setId(new QueueId(UUID.randomUUID())); - queues.add(isolatedQueue); - when(routingInfoService.getRoutingInfo(eq(tenantId))).thenReturn(new TenantRoutingInfo(tenantId, profileId, true)); + queues.add(createQueue(tenantId, 2)); + mockRoutingInfo(tenantId, profileId, true); }); - when(queueRoutingInfoService.getAllQueuesRoutingInfo()).thenReturn(queues.stream() - .map(QueueRoutingInfo::new).collect(Collectors.toList())); + mockQueues(queues); List ruleEngines = new ArrayList<>(); Map> dedicatedServers = new HashMap<>(); @@ -275,6 +260,97 @@ public class HashPartitionServiceTest { }); } + @Test + public void testPartitionChangeEvents_isolatedProfile_oneCommonServer_oneDedicated() { + ServiceInfo commonRuleEngine = ServiceInfo.newBuilder() + .setServiceId("tb-rule-engine-1") + .addAllServiceTypes(List.of(ServiceType.TB_RULE_ENGINE.name())) + .build(); + TenantProfileId tenantProfileId = new TenantProfileId(UUID.randomUUID()); + ServiceInfo dedicatedRuleEngine = ServiceInfo.newBuilder() + .setServiceId("tb-rule-engine-isolated-1") + .addAllServiceTypes(List.of(ServiceType.TB_RULE_ENGINE.name())) + .addAssignedTenantProfiles(tenantProfileId.toString()) + .build(); + + List queues = new ArrayList<>(); + Queue systemQueue = createQueue(TenantId.SYS_TENANT_ID, 10); + queues.add(systemQueue); + + TenantId tenantId = new TenantId(UUID.randomUUID()); + mockRoutingInfo(tenantId, tenantProfileId, false); // not isolated yet + mockQueues(queues); + + when(discoveryService.isService(eq(ServiceType.TB_RULE_ENGINE))).thenReturn(true); + Mockito.reset(applicationEventPublisher); + HashPartitionService partitionService_common = createPartitionService(); + partitionService_common.recalculatePartitions(commonRuleEngine, List.of(dedicatedRuleEngine)); + verifyPartitionChangeEvent(event -> { + return event.getQueueKey().getTenantId().isSysTenantId() && + event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && + event.getPartitions().stream().map(TopicPartitionInfo::getPartition).collect(Collectors.toSet()) + .size() == systemQueue.getPartitions(); + }); + + Mockito.reset(applicationEventPublisher); + HashPartitionService partitionService_dedicated = createPartitionService(); + partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); + verify(applicationEventPublisher, never()).publishEvent(any(PartitionChangeEvent.class)); + + + Queue isolatedQueue = createQueue(tenantId, 3); + queues.add(isolatedQueue); + mockQueues(queues); + mockRoutingInfo(tenantId, tenantProfileId, true); // making isolated + TransportProtos.QueueUpdateMsg queueUpdateMsg = TransportProtos.QueueUpdateMsg.newBuilder() + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .setQueueIdMSB(isolatedQueue.getUuidId().getMostSignificantBits()) + .setQueueIdLSB(isolatedQueue.getUuidId().getLeastSignificantBits()) + .setQueueName(isolatedQueue.getName()) + .setQueueTopic(isolatedQueue.getTopic()) + .setPartitions(isolatedQueue.getPartitions()) + .build(); + + partitionService_common.updateQueue(queueUpdateMsg); + partitionService_common.recalculatePartitions(commonRuleEngine, List.of(dedicatedRuleEngine)); + // expecting event about no partitions for isolated queue key + verifyPartitionChangeEvent(event -> { + return event.getQueueKey().getTenantId().equals(tenantId) && + event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && + event.getPartitions().isEmpty(); + }); + + partitionService_dedicated.updateQueue(queueUpdateMsg); + partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); + verifyPartitionChangeEvent(event -> { + return event.getQueueKey().getTenantId().equals(tenantId) && + event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && + event.getPartitions().stream().map(TopicPartitionInfo::getPartition).collect(Collectors.toSet()) + .size() == isolatedQueue.getPartitions(); + }); + + + queues = List.of(systemQueue); + mockQueues(queues); + mockRoutingInfo(tenantId, tenantProfileId, false); // turning off isolation + Mockito.reset(applicationEventPublisher); + TransportProtos.QueueDeleteMsg queueDeleteMsg = TransportProtos.QueueDeleteMsg.newBuilder() + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .setQueueIdMSB(isolatedQueue.getUuidId().getMostSignificantBits()) + .setQueueIdLSB(isolatedQueue.getUuidId().getLeastSignificantBits()) + .setQueueName(isolatedQueue.getName()) + .build(); + partitionService_dedicated.removeQueue(queueDeleteMsg); + partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); + verifyPartitionChangeEvent(event -> { + return event.getQueueKey().getTenantId().equals(tenantId) && + event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && + event.getPartitions().isEmpty(); + }); + } + @Test public void testIsManagedByCurrentServiceCheck() { TenantProfileId isolatedProfileId = new TenantProfileId(UUID.randomUUID()); @@ -282,9 +358,9 @@ public class HashPartitionServiceTest { TenantProfileId regularProfileId = new TenantProfileId(UUID.randomUUID()); TenantId isolatedTenantId = new TenantId(UUID.randomUUID()); - when(routingInfoService.getRoutingInfo(eq(isolatedTenantId))).thenReturn(new TenantRoutingInfo(isolatedTenantId, isolatedProfileId, true)); + mockRoutingInfo(isolatedTenantId, isolatedProfileId, true); TenantId regularTenantId = new TenantId(UUID.randomUUID()); - when(routingInfoService.getRoutingInfo(eq(regularTenantId))).thenReturn(new TenantRoutingInfo(regularTenantId, regularProfileId, false)); + mockRoutingInfo(regularTenantId, regularProfileId, false); assertThat(clusterRoutingService.isManagedByCurrentService(isolatedTenantId)).isTrue(); assertThat(clusterRoutingService.isManagedByCurrentService(regularTenantId)).isFalse(); @@ -296,4 +372,43 @@ public class HashPartitionServiceTest { assertThat(clusterRoutingService.isManagedByCurrentService(regularTenantId)).isTrue(); } + private void verifyPartitionChangeEvent(Predicate predicate) { + verify(applicationEventPublisher).publishEvent(argThat(event -> event instanceof PartitionChangeEvent && predicate.test((PartitionChangeEvent) event))); + } + + private void mockRoutingInfo(TenantId tenantId, TenantProfileId tenantProfileId, boolean isolatedTbRuleEngine) { + when(routingInfoService.getRoutingInfo(eq(tenantId))) + .thenReturn(new TenantRoutingInfo(tenantId, tenantProfileId, isolatedTbRuleEngine)); + } + + private void mockQueues(List queues) { + when(queueRoutingInfoService.getAllQueuesRoutingInfo()).thenReturn(queues.stream() + .map(QueueRoutingInfo::new).collect(Collectors.toList())); + } + + private Queue createQueue(TenantId tenantId, int partitions) { + Queue systemQueue = new Queue(); + systemQueue.setTenantId(tenantId); + systemQueue.setName("Main"); + systemQueue.setTopic(DataConstants.MAIN_QUEUE_TOPIC); + systemQueue.setPartitions(partitions); + systemQueue.setId(new QueueId(UUID.randomUUID())); + return systemQueue; + } + + private HashPartitionService createPartitionService() { + HashPartitionService partitionService = new HashPartitionService(discoveryService, + routingInfoService, + applicationEventPublisher, + queueRoutingInfoService); + ReflectionTestUtils.setField(partitionService, "coreTopic", "tb.core"); + ReflectionTestUtils.setField(partitionService, "corePartitions", 10); + ReflectionTestUtils.setField(partitionService, "vcTopic", "tb.vc"); + ReflectionTestUtils.setField(partitionService, "vcPartitions", 10); + ReflectionTestUtils.setField(partitionService, "hashFunctionName", hashFunctionName); + partitionService.init(); + partitionService.partitionsInit(); + return partitionService; + } + } 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 2db342d4e6..33fb350292 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 @@ -179,7 +179,6 @@ public class HashPartitionService implements PartitionService { public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); - myPartitions.remove(queueKey); partitionTopicsMap.remove(queueKey); partitionSizesMap.remove(queueKey); //TODO: remove after merging tb entity services @@ -272,12 +271,23 @@ public class HashPartitionService implements PartitionService { final ConcurrentMap> oldPartitions = myPartitions; myPartitions = newPartitions; + Set removed = new HashSet<>(); oldPartitions.forEach((queueKey, partitions) -> { - if (!myPartitions.containsKey(queueKey)) { - log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", queueKey); - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, Collections.emptySet())); + if (!newPartitions.containsKey(queueKey)) { + removed.add(queueKey); } }); + if (serviceInfoProvider.isService(ServiceType.TB_RULE_ENGINE)) { + partitionSizesMap.keySet().stream() + .filter(queueKey -> queueKey.getType() == ServiceType.TB_RULE_ENGINE && + !queueKey.getTenantId().isSysTenantId() && + !newPartitions.containsKey(queueKey)) + .forEach(removed::add); + } + removed.forEach(queueKey -> { + log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", queueKey); + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, Collections.emptySet())); + }); myPartitions.forEach((queueKey, partitions) -> { if (!partitions.equals(oldPartitions.get(queueKey))) { @@ -306,7 +316,11 @@ public class HashPartitionService implements PartitionService { if (!changes.isEmpty()) { applicationEventPublisher.publishEvent(new ClusterTopologyChangeEvent(this, changes)); responsibleServices.forEach((profileId, serviceInfos) -> { - log.info("Servers responsible for tenant profile {}: {}", profileId, toServiceIds(serviceInfos)); + if (profileId != null) { + log.info("Servers responsible for tenant profile {}: {}", profileId, toServiceIds(serviceInfos)); + } else { + log.info("Servers responsible for system queues: {}", toServiceIds(serviceInfos)); + } }); } } From bdad8454f8bdc6afcd65429ef96d304941a4e5e0 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Thu, 14 Sep 2023 08:12:30 +0300 Subject: [PATCH 039/267] Fix instructions for ubuntu and docker: styles, info --- .../centos/instructions.md | 90 +++++++++---------- .../docker/instructions.md | 10 +-- .../ubuntu/instructions.md | 72 +++++++-------- .../DefaultEdgeInstallService.java | 10 ++- .../server/controller/EdgeControllerTest.java | 2 +- .../edge-instructions-dialog.component.scss | 1 + 6 files changed, 84 insertions(+), 101 deletions(-) diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/install_instructions/centos/instructions.md index 3b0b823777..486249e320 100644 --- a/application/src/main/data/json/edge/install_instructions/centos/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/centos/instructions.md @@ -1,8 +1,6 @@ -## Install ThingsBoard Edge on CentOS/RHEL Server - Here is the list of commands, that can be used to quickly install ThingsBoard Edge on RHEL/CentOS 7/8 and connect to the cloud. -### Prerequisites +#### Prerequisites Before continue to installation execute the following commands in order to install necessary tools: ```bash @@ -10,28 +8,28 @@ sudo yum install -y nano wget sudo yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm ``` -### Install Java 11 (OpenJDK) -ThingsBoard service is running on Java 11. Follow this instructions to install OpenJDK 11: +#### Install Java 11 (OpenJDK) +ThingsBoard service is running on Java 11. Follow these instructions to install OpenJDK 11: ```bash sudo yum install java-11-openjdk +{:copy-code} ``` -{: .copy-code} Please don't forget to configure your operating system to use OpenJDK 11 by default. You can configure which version is the default using the following command: ```bash sudo update-alternatives --config java +{:copy-code} ``` -{: .copy-code} You can check the installation using the following command: ```bash java -version +{:copy-code} ``` -{: .copy-code} Expected command output is: @@ -41,15 +39,15 @@ OpenJDK Runtime Environment (...) OpenJDK 64-Bit Server VM (build ...) ``` -### Configure PostgreSQL +#### Configure PostgreSQL ThingsBoard Edge uses PostgreSQL database as a local storage. Instructions listed below will help you to install PostgreSQL. ```bash # Update your system sudo yum update +{:copy-code} ``` -{: .copy-code} **For CentOS 7:** @@ -66,8 +64,8 @@ sudo systemctl start postgresql-12 # Optional: Configure PostgreSQL to start on boot sudo systemctl enable --now postgresql-12 +{:copy-code} ``` -{: .copy-code} **For CentOS 8:** @@ -83,8 +81,8 @@ sudo systemctl start postgresql-12 # Optional: Configure PostgreSQL to start on boot sudo systemctl enable --now postgresql-12 +{:copy-code} ``` -{: .copy-code} Once PostgreSQL is installed you may want to create a new user or set the password for the the main user. The instructions below will help to set the password for main postgresql user @@ -104,8 +102,8 @@ Edit pg_hba.conf file: ```bash sudo nano /var/lib/pgsql/12/data/pg_hba.conf +{:copy-code} ``` -{: .copy-code} Locate the following lines: @@ -124,44 +122,41 @@ Finally, you should restart the PostgreSQL service to initialize the new configu ```bash sudo systemctl restart postgresql-12.service +{:copy-code} ``` -{: .copy-code} Connect to the database to create ThingsBoard Edge DB: ```bash psql -U postgres -d postgres -h 127.0.0.1 -W +{:copy-code} ``` -{: .copy-code} Execute create database statement ```bash CREATE DATABASE tb_edge; \q +{:copy-code} ``` -{: .copy-code} -### ThingsBoard Edge service installation -Download installation package. +#### ThingsBoard Edge service installation +Download installation package: ```bash -wget https://github.com/thingsboard/thingsboard-edge/releases/download/{{ site.release.edge_tag }}/tb-edge-{{ site.release.edge_ver }}.rpm +wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.rpm +{:copy-code} ``` -{: .copy-code} Go to the download repository and install ThingsBoard Edge service ```bash sudo rpm -Uvh tb-edge-${TB_EDGE_VERSION}.rpm +{:copy-code} ``` -{: .copy-code} - -### Configure ThingsBoard Edge -To configure ThingsBoard Edge, you can either manually edit the configuration file or use a command to automate the process. -#### Automated Configuration -You can use the following command to automatically update the configuration file with specific values: +#### Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -171,40 +166,33 @@ export CLOUD_RPC_HOST=${BASE_URL} export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED} EOL' +{:copy-code} ``` -{: .copy-code} -#### Manual Configuration +##### [Optional] Database Configuration +In case you changed default PostgreSQL datasource settings please update the configuration file with your actual values (**/etc/tb-edge/conf/tb-edge.conf**). +Edit ThingsBoard Edge configuration file: ```bash sudo nano /etc/tb-edge/conf/tb-edge.conf +{:copy-code} ``` -{: .copy-code} -Please update the following lines in your configuration file. Make sure to replace: +Please update the following lines in your configuration file. Make sure **to replace**: +- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource username +- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource password. -```text -export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} -export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} -export CLOUD_RPC_HOST=${BASE_URL} -export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +```bash +export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge +export SPRING_DATASOURCE_USERNAME=PUT_YOUR_POSTGRESQL_USERNAME_HERE export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE - +{:copy-code} ``` -#### [Optional] Update bind ports +##### [Optional] Update bind ports If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. -Please uncomment the following parameters in the ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): - -```text -export HTTP_BIND_PORT=18080 -export MQTT_BIND_PORT=11883 -export COAP_BIND_PORT=15683 -export LWM2M_ENABLED=false -``` - -Or update using command: +Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -213,22 +201,24 @@ export MQTT_BIND_PORT=11883 export COAP_BIND_PORT=15683 export LWM2M_ENABLED=false EOL' +{:copy-code} ``` -{: .copy-code} Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. + #### Run installation script Once ThingsBoard Edge is installed and configured please execute the following install script: ```bash sudo /usr/share/tb-edge/bin/install/install.sh +{:copy-code} ``` -{: .copy-code} -### Restart ThingsBoard Edge service +#### Restart ThingsBoard Edge service ```bash sudo service tb-edge restart +{:copy-code} ``` #### Open ThingsBoard Edge UI diff --git a/application/src/main/data/json/edge/install_instructions/docker/instructions.md b/application/src/main/data/json/edge/install_instructions/docker/instructions.md index d01986a831..e308a38076 100644 --- a/application/src/main/data/json/edge/install_instructions/docker/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/docker/instructions.md @@ -1,12 +1,10 @@ -## Install ThingsBoard Edge using Docker - Here is the list of commands, that can be used to quickly install ThingsBoard Edge using docker compose and connect to the cloud. -### Prerequisites +#### Prerequisites Install Docker CE and Docker Compose. -### Create data and logs folders +#### Create data and logs folders Run following commands, before starting docker container(s), to create folders for storing data and logs. These commands additionally will change owner of newly created folders to docker container user. @@ -18,7 +16,7 @@ mkdir -p ~/.mytb-edge-logs && sudo chown -R 799:799 ~/.mytb-edge-logs {:copy-code} ``` -### Running ThingsBoard Edge as docker service +#### Running ThingsBoard Edge as docker service ${LOCALHOST_WARNING} @@ -64,7 +62,7 @@ services: {:copy-code} ``` -#### [Optional] Update bind ports +##### [Optional] Update bind ports If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update docker compose port mapping to avoid port collision between ThingsBoard server and ThingsBoard Edge. Please update next lines of `docker-compose.yml` file: diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md index ab2bf6f8b4..21eb01654a 100644 --- a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md @@ -1,30 +1,28 @@ -## Install ThingsBoard Edge on Ubuntu Server - Here is the list of commands, that can be used to quickly install ThingsBoard Edge on Ubuntu Server and connect to the cloud. -### Install Java 11 (OpenJDK) -ThingsBoard service is running on Java 11. Follow this instructions to install OpenJDK 11: +#### Install Java 11 (OpenJDK) +ThingsBoard service is running on Java 11. Follow these instructions to install OpenJDK 11: ```bash sudo apt update sudo apt install openjdk-11-jdk +{:copy-code} ``` -{: .copy-code} Please don't forget to configure your operating system to use OpenJDK 11 by default. You can configure which version is the default using the following command: ```bash sudo update-alternatives --config java +{:copy-code} ``` -{: .copy-code} You can check the installation using the following command: ```bash java -version +{:copy-code} ``` -{: .copy-code} Expected command output is: @@ -34,7 +32,7 @@ OpenJDK Runtime Environment (...) OpenJDK 64-Bit Server VM (build ...) ``` -### Configure PostgreSQL +#### Configure PostgreSQL ThingsBoard Edge uses PostgreSQL database as a local storage. Instructions listed below will help you to install PostgreSQL. @@ -53,10 +51,10 @@ echo "deb http://apt.postgresql.org/pub/repos/apt/ ${RELEASE}"-pgdg main | sudo sudo apt update sudo apt -y install postgresql-12 sudo service postgresql start +{:copy-code} ``` -{: .copy-code} -Once PostgreSQL is installed you may want to create a new user or set the password for the the main user. +Once PostgreSQL is installed you may want to create a new user or set the password for the main user. The instructions below will help to set the password for main postgresql user ```text @@ -74,26 +72,23 @@ CREATE DATABASE tb_edge; \q ``` -### Thingsboard Edge service installation +#### Thingsboard Edge service installation Download installation package. ```bash wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.deb +{:copy-code} ``` -{: .copy-code} Go to the download repository and install ThingsBoard Edge service ```bash -sudo dpkg -i tb-edge-{TB_EDGE_VERSION}.deb +sudo dpkg -i tb-edge-${TB_EDGE_VERSION}.deb +{:copy-code} ``` -{: .copy-code} - -### Configure ThingsBoard Edge -To configure ThingsBoard Edge, you can either manually edit the configuration file or use a command to automate the process. -#### Automated Configuration -You can use the following command to automatically update the configuration file with specific values: +#### Configure ThingsBoard Edge +To configure ThingsBoard Edge, you can use the following command to automatically update the configuration file with specific values: ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -103,40 +98,33 @@ export CLOUD_RPC_HOST=${BASE_URL} export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} export CLOUD_RPC_SSL_ENABLED=${CLOUD_RPC_SSL_ENABLED} EOL' +{:copy-code} ``` -{: .copy-code} -#### Manual Configuration +##### [Optional] Database Configuration +In case you changed default PostgreSQL datasource settings please update the configuration file with your actual values (**/etc/tb-edge/conf/tb-edge.conf**). +Edit ThingsBoard Edge configuration file: ```bash sudo nano /etc/tb-edge/conf/tb-edge.conf +{:copy-code} ``` -{: .copy-code} -Please update the following lines in your configuration file. Make sure to replace: +Please update the following lines in your configuration file. Make sure **to replace**: +- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource username +- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource password. -```text -export CLOUD_ROUTING_KEY=${CLOUD_ROUTING_KEY} -export CLOUD_ROUTING_SECRET=${CLOUD_ROUTING_SECRET} -export CLOUD_RPC_HOST=${BASE_URL} -export CLOUD_RPC_PORT=${CLOUD_RPC_PORT} +```bash +export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge +export SPRING_DATASOURCE_USERNAME=PUT_YOUR_POSTGRESQL_USERNAME_HERE export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE - +{:copy-code} ``` -#### [Optional] Update bind ports +##### [Optional] Update bind ports If ThingsBoard Edge is going to be running on the same machine where ThingsBoard server (cloud) is running, you'll need to update configuration parameters to avoid port collision between ThingsBoard server and ThingsBoard Edge. -Please uncomment the following parameters in the ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): - -```text -export HTTP_BIND_PORT=18080 -export MQTT_BIND_PORT=11883 -export COAP_BIND_PORT=15683 -export LWM2M_ENABLED=false -``` - -Or update using command: +Please execute the following command to update ThingsBoard Edge configuration file (**/etc/tb-edge/conf/tb-edge.conf**): ```bash sudo sh -c 'cat <> /etc/tb-edge/conf/tb-edge.conf @@ -145,8 +133,8 @@ export MQTT_BIND_PORT=11883 export COAP_BIND_PORT=15683 export LWM2M_ENABLED=false EOL' +{:copy-code} ``` -{: .copy-code} Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. @@ -156,12 +144,14 @@ Once ThingsBoard Edge is installed and configured please execute the following i ```bash sudo /usr/share/tb-edge/bin/install/install.sh +{:copy-code} ``` #### Restart ThingsBoard Edge service ```bash sudo service tb-edge restart +{:copy-code} ``` #### Open ThingsBoard Edge UI diff --git a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java index 455b3e657a..dd17f83317 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/instructions/DefaultEdgeInstallService.java @@ -79,6 +79,9 @@ public class DefaultEdgeInstallService implements EdgeInstallService { dockerInstallInstructions = dockerInstallInstructions.replace("${LOCALHOST_WARNING}", ""); dockerInstallInstructions = dockerInstallInstructions.replace("${BASE_URL}", baseUrl); } + String edgeVersion = appVersion + "EDGE"; + edgeVersion = edgeVersion.replace("-SNAPSHOT", ""); + dockerInstallInstructions = dockerInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); dockerInstallInstructions = replacePlaceholders(dockerInstallInstructions, edge); return new EdgeInstallInstructions(dockerInstallInstructions); } @@ -87,6 +90,8 @@ public class DefaultEdgeInstallService implements EdgeInstallService { String ubuntuInstallInstructions = readFile(resolveFile("ubuntu", "instructions.md")); ubuntuInstallInstructions = replacePlaceholders(ubuntuInstallInstructions, edge); ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${BASE_URL}", request.getServerName()); + String edgeVersion = appVersion.replace("-SNAPSHOT", ""); + ubuntuInstallInstructions = ubuntuInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); return new EdgeInstallInstructions(ubuntuInstallInstructions); } @@ -95,13 +100,12 @@ public class DefaultEdgeInstallService implements EdgeInstallService { String centosInstallInstructions = readFile(resolveFile("centos", "instructions.md")); centosInstallInstructions = replacePlaceholders(centosInstallInstructions, edge); centosInstallInstructions = centosInstallInstructions.replace("${BASE_URL}", request.getServerName()); + String edgeVersion = appVersion.replace("-SNAPSHOT", ""); + centosInstallInstructions = centosInstallInstructions.replace("${TB_EDGE_VERSION}", edgeVersion); return new EdgeInstallInstructions(centosInstallInstructions); } private String replacePlaceholders(String instructions, Edge edge) { - String edgeVersion = appVersion + "EDGE"; - edgeVersion = edgeVersion.replace("-SNAPSHOT", ""); - instructions = instructions.replace("${TB_EDGE_VERSION}", edgeVersion); instructions = instructions.replace("${CLOUD_ROUTING_KEY}", edge.getRoutingKey()); instructions = instructions.replace("${CLOUD_ROUTING_SECRET}", edge.getSecret()); instructions = instructions.replace("${CLOUD_RPC_PORT}", Integer.toString(rpcPort)); diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index 081ce09ae7..1afeaff0cb 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -1107,7 +1107,7 @@ public class EdgeControllerTest extends AbstractControllerTest { public void testGetEdgeInstallInstructions() throws Exception { Edge edge = constructEdge(tenantId, "Edge for Test Docker Install Instructions", "default", "7390c3a6-69b0-9910-d155-b90aca4b772e", "l7q4zsjplzwhk16geqxy"); Edge savedEdge = doPost("/api/edge", edge, Edge.class); - String installInstructions = doGet("/api/edge/instructions/" + savedEdge.getId().getId().toString(), String.class); + String installInstructions = doGet("/api/edge/instructions/" + savedEdge.getId().getId().toString() + "/docker", String.class); Assert.assertTrue(installInstructions.contains("l7q4zsjplzwhk16geqxy")); Assert.assertTrue(installInstructions.contains("7390c3a6-69b0-9910-d155-b90aca4b772e")); } diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index 1524150330..9b4339a66c 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -69,6 +69,7 @@ :host ::ng-deep { .tb-markdown-view { + padding-top: 16px; .tb-command-code { .code-wrapper { padding: 0; From 232810309cb4a3bfcf48dfefa0d866c5810ebd3d Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 14 Sep 2023 10:00:31 +0300 Subject: [PATCH 040/267] getEdgeDockerInstallInstructions rename to getEdgeInstallInstructions, set default param 'method' --- ui-ngx/src/app/core/http/edge.service.ts | 2 +- .../home/pages/edge/edge-instructions-dialog.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/core/http/edge.service.ts b/ui-ngx/src/app/core/http/edge.service.ts index aac095412b..aeb4f7d16b 100644 --- a/ui-ngx/src/app/core/http/edge.service.ts +++ b/ui-ngx/src/app/core/http/edge.service.ts @@ -114,7 +114,7 @@ export class EdgeService { return this.http.post('/api/edge/bulk_import', entitiesData, defaultHttpOptionsFromConfig(config)); } - public getEdgeDockerInstallInstructions(edgeId: string, method: string, config?: RequestConfig): Observable { + public getEdgeInstallInstructions(edgeId: string, method: string = 'ubuntu', config?: RequestConfig): Observable { return this.http.get(`/api/edge/instructions/${edgeId}/${method}`, defaultHttpOptionsFromConfig(config)); } } diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts index 51d7e42238..99da1dfb14 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.ts @@ -85,7 +85,7 @@ export class EdgeInstructionsDialogComponent extends DialogComponent { this.contentData[method] = res.installInstructions; this.loadedInstructions = true; From f8eb27336565c836f8b0c3983e1b11bd92a6a5e3 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 14 Sep 2023 10:16:00 +0300 Subject: [PATCH 041/267] Edge instructions add top padding --- .../home/pages/edge/edge-instructions-dialog.component.scss | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index 9b4339a66c..05614add89 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -131,4 +131,8 @@ .tb-form-panel.tb-tab-body { padding: 16px 0 0; } + + .mat-mdc-tab-body { + padding: 16px 0; + } } From 5d3dd0bd8930b6f9fce61b401980d557b9e6b044 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Thu, 14 Sep 2023 11:20:49 +0200 Subject: [PATCH 042/267] fixed home page device activity widget --- ui-ngx/src/assets/dashboard/tenant_admin_home_page.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json index a2edebb7c4..37e8d82e45 100644 --- a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json +++ b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json @@ -943,7 +943,7 @@ "keyFilters": [ { "key": { - "type": "ATTRIBUTE", + "type": "SERVER_ATTRIBUTE", "key": "active" }, "valueType": "BOOLEAN", @@ -975,7 +975,7 @@ "keyFilters": [ { "key": { - "type": "ATTRIBUTE", + "type": "SERVER_ATTRIBUTE", "key": "active" }, "valueType": "BOOLEAN", @@ -1051,4 +1051,4 @@ }, "externalId": null, "name": "Tenant Administrator Home Page" -} \ No newline at end of file +} From 966af7b825066f36030e4b8d4f4069a9b4fce2b5 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Thu, 14 Sep 2023 12:23:05 +0300 Subject: [PATCH 043/267] Edge instructions fix padding --- .../pages/edge/edge-instructions-dialog.component.scss | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index 05614add89..0c561cd8f6 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -69,7 +69,7 @@ :host ::ng-deep { .tb-markdown-view { - padding-top: 16px; + padding: 16px; .tb-command-code { .code-wrapper { padding: 0; @@ -112,9 +112,9 @@ } } } - > p, h1, h2, h3, h4, h5, div { - padding-left: 16px !important; - padding-right: 16px !important; + & > *:not(ul) { + padding-right: unset !important; + padding-left: unset !important; } } .mdc-button__label > span { From babc8844e9a552b910ace2779327a1cbef4ad623 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 14 Sep 2023 12:58:04 +0300 Subject: [PATCH 044/267] Add last reported activity in the past fix, cover with a test --- .../state/DefaultDeviceStateService.java | 4 + .../state/DefaultDeviceStateServiceTest.java | 102 ++++++++++++++++++ 2 files changed, 106 insertions(+) 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 1f9239cea3..41a41f5e82 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 @@ -250,6 +250,10 @@ public class DefaultDeviceStateService extends AbstractPartitionBasedService provideParametersForUpdateActivityState() { + return Stream.of( + Arguments.of(true, 100, 120, 80, 80, false, false), + + Arguments.of(true, 100, 120, 100, 100, false, false), + + Arguments.of(false, 100, 120, 110, 110, false, true), + + + Arguments.of(true, 100, 100, 80, 80, false, false), + + Arguments.of(true, 100, 100, 100, 100, false, false), + + Arguments.of(false, 100, 100, 110, 0, true, true), + + + Arguments.of(false, 100, 110, 110, 0, true, true), + + Arguments.of(false, 100, 110, 120, 0, true, true), + + + Arguments.of(true, 0, 0, 0, 0, false, false), + + Arguments.of(false, 0, 0, 0, 0, true, true) + ); + } + @ParameterizedTest @MethodSource("provideParametersForDecreaseInactivityTimeout") public void givenTestParameters_whenOnDeviceInactivityTimeout_thenShouldBeInTheExpectedStateAndPerformExpectedActions( From 092e3b07c149d732746a7cc58648e4dc8314d0c7 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Thu, 14 Sep 2023 13:44:51 +0300 Subject: [PATCH 045/267] Minor improvements for edge centos/ubuntu instruction. css minor updates --- .../centos/instructions.md | 19 +++--- .../ubuntu/instructions.md | 17 +++--- .../edge-instructions-dialog.component.scss | 61 +++++++------------ 3 files changed, 40 insertions(+), 57 deletions(-) diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/install_instructions/centos/instructions.md index 486249e320..0e9bf251c3 100644 --- a/application/src/main/data/json/edge/install_instructions/centos/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/centos/instructions.md @@ -84,8 +84,8 @@ sudo systemctl enable --now postgresql-12 {:copy-code} ``` -Once PostgreSQL is installed you may want to create a new user or set the password for the the main user. -The instructions below will help to set the password for main postgresql user +Once PostgreSQL is installed you may want to create a new user or set the password for the main user. +The instructions below will help to set the password for main PostgreSQL user: ```text sudo su - postgres @@ -132,7 +132,7 @@ psql -U postgres -d postgres -h 127.0.0.1 -W {:copy-code} ``` -Execute create database statement +Execute create database statement: ```bash CREATE DATABASE tb_edge; @@ -148,7 +148,7 @@ wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDG {:copy-code} ``` -Go to the download repository and install ThingsBoard Edge service +Go to the download repository and install ThingsBoard Edge service: ```bash sudo rpm -Uvh tb-edge-${TB_EDGE_VERSION}.rpm @@ -170,8 +170,7 @@ EOL' ``` ##### [Optional] Database Configuration -In case you changed default PostgreSQL datasource settings please update the configuration file with your actual values (**/etc/tb-edge/conf/tb-edge.conf**). -Edit ThingsBoard Edge configuration file: +In case you changed default PostgreSQL datasource settings (**postgres**/**postgres**) please update the configuration file (**/etc/tb-edge/conf/tb-edge.conf**) with your actual values: ```bash sudo nano /etc/tb-edge/conf/tb-edge.conf @@ -179,12 +178,12 @@ sudo nano /etc/tb-edge/conf/tb-edge.conf ``` Please update the following lines in your configuration file. Make sure **to replace**: -- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource username -- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource password. +- Replace 'postgres' with your actual PostgreSQL username; +- Replace 'PUT_YOUR_POSTGRESQL_PASSWORD_HERE' with your actual PostgreSQL password. ```bash export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge -export SPRING_DATASOURCE_USERNAME=PUT_YOUR_POSTGRESQL_USERNAME_HERE +export SPRING_DATASOURCE_USERNAME=postgres export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE {:copy-code} ``` @@ -204,7 +203,7 @@ EOL' {:copy-code} ``` -Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. +Make sure that ports above (18080, 11883, 15683) are not used by any other application. #### Run installation script Once ThingsBoard Edge is installed and configured please execute the following install script: diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md index 21eb01654a..72b85e5190 100644 --- a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md @@ -55,7 +55,7 @@ sudo service postgresql start ``` Once PostgreSQL is installed you may want to create a new user or set the password for the main user. -The instructions below will help to set the password for main postgresql user +The instructions below will help to set the password for main PostgreSQL user: ```text sudo su - postgres @@ -73,14 +73,14 @@ CREATE DATABASE tb_edge; ``` #### Thingsboard Edge service installation -Download installation package. +Download installation package: ```bash wget https://github.com/thingsboard/thingsboard-edge/releases/download/v${TB_EDGE_VERSION}/tb-edge-${TB_EDGE_VERSION}.deb {:copy-code} ``` -Go to the download repository and install ThingsBoard Edge service +Go to the download repository and install ThingsBoard Edge service: ```bash sudo dpkg -i tb-edge-${TB_EDGE_VERSION}.deb @@ -102,8 +102,7 @@ EOL' ``` ##### [Optional] Database Configuration -In case you changed default PostgreSQL datasource settings please update the configuration file with your actual values (**/etc/tb-edge/conf/tb-edge.conf**). -Edit ThingsBoard Edge configuration file: +In case you changed default PostgreSQL datasource settings (**postgres**/**postgres**) please update the configuration file (**/etc/tb-edge/conf/tb-edge.conf**) with your actual values: ```bash sudo nano /etc/tb-edge/conf/tb-edge.conf @@ -111,12 +110,12 @@ sudo nano /etc/tb-edge/conf/tb-edge.conf ``` Please update the following lines in your configuration file. Make sure **to replace**: -- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource username -- PUT_YOUR_POSTGRESQL_PASSWORD_HERE with your actual postgres datasource password. +- Replace 'postgres' with your actual PostgreSQL username; +- Replace 'PUT_YOUR_POSTGRESQL_PASSWORD_HERE' with your actual PostgreSQL password. ```bash export SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/tb_edge -export SPRING_DATASOURCE_USERNAME=PUT_YOUR_POSTGRESQL_USERNAME_HERE +export SPRING_DATASOURCE_USERNAME=postgres export SPRING_DATASOURCE_PASSWORD=PUT_YOUR_POSTGRESQL_PASSWORD_HERE {:copy-code} ``` @@ -136,7 +135,7 @@ EOL' {:copy-code} ``` -Make sure that ports above (18080, 11883, 15683-15688) are not used by any other application. +Make sure that ports above (18080, 11883, 15683) are not used by any other application. #### Run installation script diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index 0c561cd8f6..a22671248a 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -69,48 +69,33 @@ :host ::ng-deep { .tb-markdown-view { - padding: 16px; - .tb-command-code { - .code-wrapper { - padding: 0; - pre[class*=language-] { - margin: 0; - background: #F3F6FA; - border-color: #305680; - padding-right: 38px; - overflow: scroll; - padding-bottom: 4px; - - &::-webkit-scrollbar { - width: 4px; - height: 4px; - } - } + padding: 16px 16px 32px 16px; + div.code-wrapper button.clipboard-btn { + right: -2px !important; + p { + color: #305680; } - button.clipboard-btn { - right: -2px; - p { - color: #305680; - } - p, div { - background-color: #F3F6FA; + p, div { + background-color: #F3F6FA; + } + div { + img { + display: none; } - div { - img { - display: none; - } - &:after { - content: ""; - position: initial; - display: block; - width: 18px; - height: 18px; - background: #305680; - mask-image: url(/assets/copy-code-icon.svg); - mask-repeat: no-repeat; - } + &:after { + content: ""; + position: initial; + display: block; + width: 18px; + height: 18px; + background: #305680; + mask-image: url(/assets/copy-code-icon.svg); + mask-repeat: no-repeat; } } + &.multiline { + right: -2px !important; + } } & > *:not(ul) { padding-right: unset !important; From 1a272d25955733cc1bcbfb9164ac118a956a717c Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 14 Sep 2023 15:20:07 +0300 Subject: [PATCH 046/267] UI: Add notification popover loadings state --- .../show-notification-popover.component.html | 40 +++++++++++-------- .../show-notification-popover.component.ts | 10 ++++- .../websocket/notification-ws.models.ts | 2 +- .../assets/locale/locale.constant-en_US.json | 1 + 4 files changed, 35 insertions(+), 18 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.html b/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.html index 0a0a5e3cdb..fa622c30bf 100644 --- a/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.html +++ b/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.html @@ -24,24 +24,32 @@
-
-
-
- - - -
+ +
+
+
+ + + +
+
+
+ +
+
-
- -
- -
+ empty notification notification.no-notifications-yet + +
+ +
notification.loading-notifications
+
+
diff --git a/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.ts b/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.ts index 5e94289055..b2a9009a57 100644 --- a/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.ts +++ b/ui-ngx/src/app/modules/home/components/notification/show-notification-popover.component.ts @@ -22,7 +22,7 @@ import { AppState } from '@core/core.state'; import { Notification, NotificationRequest } from '@shared/models/notification.models'; import { NotificationWebsocketService } from '@core/ws/notification-websocket.service'; import { BehaviorSubject, Observable, ReplaySubject, Subscription } from 'rxjs'; -import { share, tap } from 'rxjs/operators'; +import { map, share, tap } from 'rxjs/operators'; import { Router } from '@angular/router'; import { NotificationSubscriber } from '@shared/models/websocket/notification-ws.models'; @@ -46,6 +46,7 @@ export class ShowNotificationPopoverComponent extends PageComponent implements O private notificationCountSubscriber: Subscription; notifications$: Observable; + loadNotification = false; constructor(protected store: Store, private notificationWsService: NotificationWebsocketService, @@ -58,6 +59,13 @@ export class ShowNotificationPopoverComponent extends PageComponent implements O ngOnInit() { this.notificationSubscriber = NotificationSubscriber.createNotificationsSubscription(this.notificationWsService, this.zone, 6); this.notifications$ = this.notificationSubscriber.notifications$.pipe( + map(value => { + if (Array.isArray(value)) { + this.loadNotification = true; + return value; + } + return []; + }), share({ connector: () => new ReplaySubject(1) }), diff --git a/ui-ngx/src/app/shared/models/websocket/notification-ws.models.ts b/ui-ngx/src/app/shared/models/websocket/notification-ws.models.ts index 0acbba1139..dffa828ae1 100644 --- a/ui-ngx/src/app/shared/models/websocket/notification-ws.models.ts +++ b/ui-ngx/src/app/shared/models/websocket/notification-ws.models.ts @@ -52,7 +52,7 @@ export class NotificationSubscriber extends WsSubscriber { cmdUpdateType: undefined, errorCode: 0, errorMsg: '', - notifications: [], + notifications: null, totalUnreadCount: 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 6feb6580e7..1ca51bdf39 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3201,6 +3201,7 @@ "dashboard": "Open dashboard", "link": "Open URL link" }, + "loading-notifications": "Loading notifications...", "management": "Notification management", "mark-all-as-read": "Mark all as read", "mark-as-read": "Mark as read", From 0d8a2549d959b59fb4053195d1e57eb0cbd8f848 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 14 Sep 2023 15:22:53 +0300 Subject: [PATCH 047/267] Single PartitionChangeEvent after recalculatePartitions --- .../actors/service/DefaultActorService.java | 2 +- .../DefaultTbRuleEngineConsumerService.java | 28 ++++++++++--------- .../discovery/HashPartitionServiceTest.java | 22 ++++++--------- .../state/DefaultDeviceStateServiceTest.java | 4 ++- .../common/msg/queue/PartitionChangeMsg.java | 4 --- .../queue/discovery/HashPartitionService.java | 16 +++++++++-- .../discovery/event/PartitionChangeEvent.java | 18 +++++++----- 7 files changed, 52 insertions(+), 42 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java index dd5bd4f1ed..380da71443 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java @@ -121,7 +121,7 @@ public class DefaultActorService extends TbApplicationEventListener { + String serviceQueue = queueKey.getQueueName(); + log.info("[{}] Subscribing to partitions: {}", serviceQueue, partitions); + Queue configuration = consumerConfigurations.get(queueKey); + if (configuration == null) { + log.warn("Received invalid partition change event for {} that is not managed by this service", queueKey); + return; + } + if (!configuration.isConsumerPerPartition()) { + consumers.get(queueKey).subscribe(partitions); + } else { + log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, partitions); + subscribeConsumerPerPartition(queueKey, partitions); + } + }); } } diff --git a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java index 5e800d52a5..49008ab559 100644 --- a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java @@ -286,10 +286,8 @@ public class HashPartitionServiceTest { HashPartitionService partitionService_common = createPartitionService(); partitionService_common.recalculatePartitions(commonRuleEngine, List.of(dedicatedRuleEngine)); verifyPartitionChangeEvent(event -> { - return event.getQueueKey().getTenantId().isSysTenantId() && - event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && - event.getPartitions().stream().map(TopicPartitionInfo::getPartition).collect(Collectors.toSet()) - .size() == systemQueue.getPartitions(); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, DataConstants.MAIN_QUEUE_NAME, TenantId.SYS_TENANT_ID); + return event.getPartitionsMap().get(queueKey).size() == systemQueue.getPartitions(); }); Mockito.reset(applicationEventPublisher); @@ -316,18 +314,15 @@ public class HashPartitionServiceTest { partitionService_common.recalculatePartitions(commonRuleEngine, List.of(dedicatedRuleEngine)); // expecting event about no partitions for isolated queue key verifyPartitionChangeEvent(event -> { - return event.getQueueKey().getTenantId().equals(tenantId) && - event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && - event.getPartitions().isEmpty(); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, DataConstants.MAIN_QUEUE_NAME, tenantId); + return event.getPartitionsMap().get(queueKey).isEmpty(); }); partitionService_dedicated.updateQueue(queueUpdateMsg); partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); verifyPartitionChangeEvent(event -> { - return event.getQueueKey().getTenantId().equals(tenantId) && - event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && - event.getPartitions().stream().map(TopicPartitionInfo::getPartition).collect(Collectors.toSet()) - .size() == isolatedQueue.getPartitions(); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, DataConstants.MAIN_QUEUE_NAME, tenantId); + return event.getPartitionsMap().get(queueKey).size() == isolatedQueue.getPartitions(); }); @@ -345,9 +340,8 @@ public class HashPartitionServiceTest { partitionService_dedicated.removeQueue(queueDeleteMsg); partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); verifyPartitionChangeEvent(event -> { - return event.getQueueKey().getTenantId().equals(tenantId) && - event.getQueueKey().getQueueName().equals(DataConstants.MAIN_QUEUE_NAME) && - event.getPartitions().isEmpty(); + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, DataConstants.MAIN_QUEUE_NAME, tenantId); + return event.getPartitionsMap().get(queueKey).isEmpty(); }); } diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index ccb0b5e26c..adb46affe8 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -160,7 +160,9 @@ public class DefaultDeviceStateServiceTest { Mockito.reset(service, telemetrySubscriptionService); ReflectionTestUtils.setField(service, "defaultInactivityTimeoutMs", timeout); service.init(); - PartitionChangeEvent event = new PartitionChangeEvent(this, new QueueKey(ServiceType.TB_CORE), Collections.singleton(tpi)); + PartitionChangeEvent event = new PartitionChangeEvent(this, ServiceType.TB_CORE, Map.of( + new QueueKey(ServiceType.TB_CORE), Collections.singleton(tpi) + )); service.onApplicationEvent(event); Thread.sleep(100); } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java index 39d7dad2db..fd48b36e67 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/PartitionChangeMsg.java @@ -20,8 +20,6 @@ import lombok.Getter; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.TbActorMsg; -import java.util.Set; - /** * @author Andrew Shvayka */ @@ -30,8 +28,6 @@ public final class PartitionChangeMsg implements TbActorMsg { @Getter private final ServiceType serviceType; - @Getter - private final Set partitions; @Override public MsgType getMsgType() { 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 33fb350292..1974c82ec4 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 @@ -271,6 +271,8 @@ public class HashPartitionService implements PartitionService { final ConcurrentMap> oldPartitions = myPartitions; myPartitions = newPartitions; + Map> changedPartitionsMap = new HashMap<>(); + Set removed = new HashSet<>(); oldPartitions.forEach((queueKey, partitions) -> { if (!newPartitions.containsKey(queueKey)) { @@ -286,7 +288,7 @@ public class HashPartitionService implements PartitionService { } removed.forEach(queueKey -> { log.info("[{}] NO MORE PARTITIONS FOR CURRENT KEY", queueKey); - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, Collections.emptySet())); + changedPartitionsMap.put(queueKey, Collections.emptySet()); }); myPartitions.forEach((queueKey, partitions) -> { @@ -295,9 +297,19 @@ public class HashPartitionService implements PartitionService { Set tpiList = partitions.stream() .map(partition -> buildTopicPartitionInfo(queueKey, partition)) .collect(Collectors.toSet()); - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, queueKey, tpiList)); + changedPartitionsMap.put(queueKey, tpiList); } }); + if (!changedPartitionsMap.isEmpty()) { + Map>> partitionsByServiceType = new HashMap<>(); + changedPartitionsMap.forEach((queueKey, partitions) -> { + partitionsByServiceType.computeIfAbsent(queueKey.getType(), serviceType -> new HashMap<>()) + .put(queueKey, partitions); + }); + partitionsByServiceType.forEach((serviceType, partitionsMap) -> { + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceType, partitionsMap)); + }); + } if (currentOtherServices == null) { currentOtherServices = new ArrayList<>(otherServices); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java index c7a00daa1c..0d74cdfaee 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java @@ -21,6 +21,8 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.queue.discovery.QueueKey; +import java.util.Collections; +import java.util.Map; import java.util.Set; @ToString(callSuper = true) @@ -29,17 +31,19 @@ public class PartitionChangeEvent extends TbApplicationEvent { private static final long serialVersionUID = -8731788167026510559L; @Getter - private final QueueKey queueKey; + private final ServiceType serviceType; @Getter - private final Set partitions; + private final Map> partitionsMap; - public PartitionChangeEvent(Object source, QueueKey queueKey, Set partitions) { + public PartitionChangeEvent(Object source, ServiceType serviceType, Map> partitionsMap) { super(source); - this.queueKey = queueKey; - this.partitions = partitions; + this.serviceType = serviceType; + this.partitionsMap = partitionsMap; } - public ServiceType getServiceType() { - return queueKey.getType(); + // only for service types that have single QueueKey + public Set getPartitions() { + return partitionsMap.values().stream().findAny().orElse(Collections.emptySet()); } + } From a768880d6dcf6697bb4e0daaca82644882c09465 Mon Sep 17 00:00:00 2001 From: Andrew Shvayka Date: Thu, 14 Sep 2023 15:47:29 +0300 Subject: [PATCH 048/267] Revert "fixed home page device activity widget" --- ui-ngx/src/assets/dashboard/tenant_admin_home_page.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json index 37e8d82e45..a2edebb7c4 100644 --- a/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json +++ b/ui-ngx/src/assets/dashboard/tenant_admin_home_page.json @@ -943,7 +943,7 @@ "keyFilters": [ { "key": { - "type": "SERVER_ATTRIBUTE", + "type": "ATTRIBUTE", "key": "active" }, "valueType": "BOOLEAN", @@ -975,7 +975,7 @@ "keyFilters": [ { "key": { - "type": "SERVER_ATTRIBUTE", + "type": "ATTRIBUTE", "key": "active" }, "valueType": "BOOLEAN", @@ -1051,4 +1051,4 @@ }, "externalId": null, "name": "Tenant Administrator Home Page" -} +} \ No newline at end of file From 65a4f002bbbdcc9f1a057a43f9fdd82902923ae0 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 14 Sep 2023 15:49:48 +0300 Subject: [PATCH 049/267] Fix copy-paste error --- .../server/service/state/DefaultDeviceStateServiceTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java index 06cde65c36..746da9a8f0 100644 --- a/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/state/DefaultDeviceStateServiceTest.java @@ -363,7 +363,7 @@ public class DefaultDeviceStateServiceTest { service.deviceStates.put(deviceId, deviceStateDataMock); // WHEN - service.updateActivityState(deviceId, deviceStateDataMock, System.currentTimeMillis()); + service.updateActivityState(deviceId, null, System.currentTimeMillis()); // THEN assertThat(service.deviceStates.get(deviceId)).isNull(); From 4e526aa969bd446ee2b679b2cc7e555869f37ba9 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 14 Sep 2023 16:27:23 +0300 Subject: [PATCH 050/267] Queue removal: always publish PartitionChangeEvent; remove redundant recalculatePartitions; add debug log --- .../DefaultTbRuleEngineConsumerService.java | 2 -- .../queue/discovery/HashPartitionService.java | 24 ++++++++++++++++--- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index f67d80cb1b..c715b7b03c 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -188,7 +188,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< log.info("[{}] Subscribing to partitions: {}", serviceQueue, partitions); Queue configuration = consumerConfigurations.get(queueKey); if (configuration == null) { - log.warn("Received invalid partition change event for {} that is not managed by this service", queueKey); return; } if (!configuration.isConsumerPerPartition()) { @@ -503,7 +502,6 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } } - partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { 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 1974c82ec4..5be5caf6ff 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 @@ -179,10 +179,15 @@ public class HashPartitionService implements PartitionService { public void removeQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); + myPartitions.remove(queueKey); partitionTopicsMap.remove(queueKey); partitionSizesMap.remove(queueKey); //TODO: remove after merging tb entity services removeTenant(tenantId); + + if (serviceInfoProvider.isService(ServiceType.TB_RULE_ENGINE)) { + publishPartitionChangeEvent(ServiceType.TB_RULE_ENGINE, Map.of(queueKey, Collections.emptySet())); + } } @Override @@ -306,9 +311,7 @@ public class HashPartitionService implements PartitionService { partitionsByServiceType.computeIfAbsent(queueKey.getType(), serviceType -> new HashMap<>()) .put(queueKey, partitions); }); - partitionsByServiceType.forEach((serviceType, partitionsMap) -> { - applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceType, partitionsMap)); - }); + partitionsByServiceType.forEach(this::publishPartitionChangeEvent); } if (currentOtherServices == null) { @@ -340,6 +343,18 @@ public class HashPartitionService implements PartitionService { applicationEventPublisher.publishEvent(new ServiceListChangedEvent(otherServices, currentService)); } + private void publishPartitionChangeEvent(ServiceType serviceType, Map> partitionsMap) { + if (log.isDebugEnabled()) { + log.debug("Publishing partition change event for service type " + serviceType + ":" + System.lineSeparator() + + partitionsMap.entrySet().stream() + .map(entry -> entry.getKey() + " - " + entry.getValue().stream() + .map(TopicPartitionInfo::getFullTopicName).sorted() + .collect(Collectors.toList())) + .collect(Collectors.joining(System.lineSeparator()))); + } + applicationEventPublisher.publishEvent(new PartitionChangeEvent(this, serviceType, partitionsMap)); + } + @Override public Set getAllServiceIds(ServiceType serviceType) { return getAllServices(serviceType).stream().map(ServiceInfo::getServiceId).collect(Collectors.toSet()); @@ -505,6 +520,9 @@ public class HashPartitionService implements PartitionService { } responsibleServices.put(profileId, responsible); } + if (responsible.isEmpty()) { + return null; + } servers = responsible; } From 3ddb36c979a373b060f39551f411a3000c76b10e Mon Sep 17 00:00:00 2001 From: Dmitriymush Date: Thu, 14 Sep 2023 16:42:36 +0300 Subject: [PATCH 051/267] PROD-2415: changes to modules that overrides default dialogs behaviour --- ui-ngx/src/app/core/core.module.ts | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/core.module.ts b/ui-ngx/src/app/core/core.module.ts index 837d530fbf..b4471adf36 100644 --- a/ui-ngx/src/app/core/core.module.ts +++ b/ui-ngx/src/app/core/core.module.ts @@ -34,7 +34,7 @@ import { import { TranslateHttpLoader } from '@ngx-translate/http-loader'; import { TbMissingTranslationHandler } from './translate/missing-translate-handler'; import { MatButtonModule } from '@angular/material/button'; -import { MatDialogModule } from '@angular/material/dialog'; +import { MAT_DIALOG_DEFAULT_OPTIONS, MatDialogModule } from '@angular/material/dialog'; import { MatSnackBarModule } from '@angular/material/snack-bar'; import { FlexLayoutModule } from '@angular/flex-layout'; import { TranslateDefaultCompiler } from '@core/translate/translate-default-compiler'; @@ -100,6 +100,12 @@ export function HttpLoaderFactory(http: HttpClient) { useClass: GlobalHttpInterceptor, multi: true }, + { + provide: MAT_DIALOG_DEFAULT_OPTIONS, + useValue: { + restoreFocus: false + } + }, WINDOW_PROVIDERS ], exports: [] From bbc3d16b44f1143f2cd5983bd8a92e0c56474d90 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Thu, 14 Sep 2023 17:57:10 +0300 Subject: [PATCH 052/267] UI: Added default color for mat-hint; Added onTouch event for string items list component --- .../app/shared/components/string-items-list.component.html | 1 + .../src/app/shared/components/string-items-list.component.ts | 5 +++-- ui-ngx/src/theme-overwrites.scss | 5 +++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/string-items-list.component.html b/ui-ngx/src/app/shared/components/string-items-list.component.html index 7416e96870..41723ce3d7 100644 --- a/ui-ngx/src/app/shared/components/string-items-list.component.html +++ b/ui-ngx/src/app/shared/components/string-items-list.component.html @@ -29,6 +29,7 @@ close { - }; + onTouched = () => {}; + private propagateChange: (value: any) => void = () => {}; private dirty = false; constructor(private fb: FormBuilder) { @@ -159,6 +159,7 @@ export class StringItemsListComponent implements ControlValueAccessor, OnInit { } registerOnTouched(fn: any): void { + this.onTouched = fn; } setDisabledState(isDisabled: boolean): void { diff --git a/ui-ngx/src/theme-overwrites.scss b/ui-ngx/src/theme-overwrites.scss index 6b4995664e..f16eead0e1 100644 --- a/ui-ngx/src/theme-overwrites.scss +++ b/ui-ngx/src/theme-overwrites.scss @@ -52,6 +52,11 @@ } } } + .mat-mdc-form-field { + .mat-mdc-form-field-hint-wrapper { + color: rgba(0, 0, 0, 0.6); + } + } } @mixin _mat-button-overwrites($primary, $config-or-theme) { From e255b6ec42e9a387997ac8dc5c166e241f1fecb2 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 14 Sep 2023 18:45:22 +0300 Subject: [PATCH 053/267] UI: Add Alarm and entity count widgets. --- .../system/widget_bundles/alarm_widgets.json | 5 +- .../system/widget_bundles/count_widgets.json | 14 ++ .../system/widget_bundles/entity_widgets.json | 1 + .../json/system/widget_types/alarm_count.json | 23 ++ .../system/widget_types/entity_count.json | 23 ++ .../DefaultSystemDataLoaderService.java | 1 + .../alarm-count-basic-config.component.html | 61 ++++++ .../alarm-count-basic-config.component.ts | 107 ++++++++++ .../alarms-table-basic-config.component.html | 25 ++- .../alarms-table-basic-config.component.ts | 14 ++ .../basic/basic-widget-config.module.ts | 20 +- ...entities-table-basic-config.component.html | 0 .../entities-table-basic-config.component.ts | 0 .../entity-count-basic-config.component.html | 56 +++++ .../entity-count-basic-config.component.ts | 98 +++++++++ .../widget/config/datasource.component.html | 6 +- .../widget/config/datasource.component.ts | 8 + .../widget/config/datasources.component.html | 2 +- .../widget/config/datasources.component.ts | 15 +- .../alarms-table-widget.component.html | 0 .../alarms-table-widget.component.scss | 0 .../alarms-table-widget.component.ts | 2 +- .../lib/count/count-widget.component.html | 37 ++++ .../lib/count/count-widget.component.scss | 80 +++++++ .../lib/count/count-widget.component.ts | 148 +++++++++++++ .../widget/lib/count/count-widget.models.ts | 122 +++++++++++ .../entities-hierarchy-widget.component.html | 0 .../entities-hierarchy-widget.component.scss | 0 .../entities-hierarchy-widget.component.ts | 2 +- .../entities-hierarchy-widget.models.ts | 0 .../entities-table-widget.component.html | 0 .../entities-table-widget.component.scss | 0 .../entities-table-widget.component.ts | 2 +- ...alarm-count-widget-settings.component.html | 23 ++ .../alarm-count-widget-settings.component.ts | 62 ++++++ .../alarms-table-widget-settings.component.ts | 1 + .../count-widget-settings.component.html | 103 +++++++++ .../common/count-widget-settings.component.ts | 201 ++++++++++++++++++ .../common/widget-settings-common.module.ts | 9 +- ...s-hierarchy-widget-settings.component.html | 0 ...ies-hierarchy-widget-settings.component.ts | 0 ...entities-table-key-settings.component.html | 0 .../entities-table-key-settings.component.ts | 0 ...ities-table-widget-settings.component.html | 0 ...ntities-table-widget-settings.component.ts | 0 ...ntity-count-widget-settings.component.html | 23 ++ .../entity-count-widget-settings.component.ts | 62 ++++++ .../lib/settings/widget-settings.module.ts | 24 ++- .../widget/widget-component.service.ts | 3 + .../widget/widget-components.module.ts | 13 +- .../widget/widget-config.component.ts | 2 +- .../material-icon-select.component.html | 3 +- .../material-icon-select.component.ts | 3 + .../shared/models/widget-settings.models.ts | 26 ++- ui-ngx/src/app/shared/models/widget.models.ts | 1 + .../assets/locale/locale.constant-en_US.json | 19 +- .../widget/alarm-count/column-layout.svg | 21 ++ .../assets/widget/alarm-count/row-layout.svg | 21 ++ .../widget/entity-count/column-layout.svg | 21 ++ .../assets/widget/entity-count/row-layout.svg | 21 ++ 60 files changed, 1500 insertions(+), 34 deletions(-) create mode 100644 application/src/main/data/json/system/widget_bundles/count_widgets.json create mode 100644 application/src/main/data/json/system/widget_types/alarm_count.json create mode 100644 application/src/main/data/json/system/widget_types/entity_count.json create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts rename ui-ngx/src/app/modules/home/components/widget/config/basic/{cards => entity}/entities-table-basic-config.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/config/basic/{cards => entity}/entities-table-basic-config.component.ts (100%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts rename ui-ngx/src/app/modules/home/components/widget/lib/{ => alarm}/alarms-table-widget.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => alarm}/alarms-table-widget.component.scss (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => alarm}/alarms-table-widget.component.ts (99%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-hierarchy-widget.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-hierarchy-widget.component.scss (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-hierarchy-widget.component.ts (99%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-hierarchy-widget.models.ts (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-table-widget.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-table-widget.component.scss (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/{ => entity}/entities-table-widget.component.ts (99%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-hierarchy-widget-settings.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-hierarchy-widget-settings.component.ts (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-table-key-settings.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-table-key-settings.component.ts (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-table-widget-settings.component.html (100%) rename ui-ngx/src/app/modules/home/components/widget/lib/settings/{cards => entity}/entities-table-widget-settings.component.ts (100%) create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts create mode 100644 ui-ngx/src/assets/widget/alarm-count/column-layout.svg create mode 100644 ui-ngx/src/assets/widget/alarm-count/row-layout.svg create mode 100644 ui-ngx/src/assets/widget/entity-count/column-layout.svg create mode 100644 ui-ngx/src/assets/widget/entity-count/row-layout.svg diff --git a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json index 42cbd9b262..4ca5484223 100644 --- a/application/src/main/data/json/system/widget_bundles/alarm_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/alarm_widgets.json @@ -2,12 +2,13 @@ "widgetsBundle": { "alias": "alarm_widgets", "title": "Alarm widgets", - "image": "data:image/png;base64,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", + "image": "data:image/png;base64,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", "description": "Visualization of alarms for devices, assets and other entities.", "externalId": null, "name": "Alarm widgets" }, "widgetTypeFqns": [ - "alarm_widgets.alarms_table" + "alarm_widgets.alarms_table", + "alarm_count" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/count_widgets.json b/application/src/main/data/json/system/widget_bundles/count_widgets.json new file mode 100644 index 0000000000..a40f33cd8e --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/count_widgets.json @@ -0,0 +1,14 @@ +{ + "widgetsBundle": { + "alias": "count_widgets", + "title": "Count widgets", + "image": "data:image/png;base64,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", + "description": "Cards to display the number of alarms or entities based on selected filter.", + "externalId": null, + "name": "Count widgets" + }, + "widgetTypeFqns": [ + "alarm_count", + "entity_count" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/entity_widgets.json b/application/src/main/data/json/system/widget_bundles/entity_widgets.json index 865d2e11ec..32ceedb4c1 100644 --- a/application/src/main/data/json/system/widget_bundles/entity_widgets.json +++ b/application/src/main/data/json/system/widget_bundles/entity_widgets.json @@ -9,6 +9,7 @@ }, "widgetTypeFqns": [ "cards.entities_table", + "entity_count", "cards.entities_hierarchy" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/alarm_count.json b/application/src/main/data/json/system/widget_types/alarm_count.json new file mode 100644 index 0000000000..dd3b63e3ae --- /dev/null +++ b/application/src/main/data/json/system/widget_types/alarm_count.json @@ -0,0 +1,23 @@ +{ + "fqn": "alarm_count", + "name": "Alarm count", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAolBMVEXg4ODf39/g4OAAAADg4ODf39/////g4OD8/Pz+/v7RJzD29vb6+vr7+/v09PTt7e3z8/P4+Pjx8fHv7+/ok5fXQkqXl5chISHk5OTIyMi6urqpqamgoKDDw8P55OXurrI8PDzc3NyxsbF0dHRYWFjlhYrUND3V1dXroKT88fLR0dHzycvwu76QkJDieH7eY2pKSkovLy/219jieH1mZmbTND12Tj45AAAABnRSTlPvIL8Ar7DvmsykAAAEx0lEQVR42u2aiXLaMBBATdMuUmU5yEBJgEDanL3v//+1rpDI2khA087U63RfjGRJa4k3a5sMpjgZPCuGfef54KQYFGMFPUfVqPG8hifAGE+r3ufDo4piCE+CoYgwQ0S4ISLcEBFuiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S48X+IaDiKBibsiGit/hit/i06J0IatkRsaWPZxoZR3OIgheKYjUHbkoLj/jawOWOjsDQ3rUfTUXcIQ5c9IqhROlPlMf5lwm6saYx2KC4dJSg6BhsKzMZTBK3hSqV0XsQ6p9ic9EexximtMyJaOdMfDURjTnIiyrqe/d5fOauyIgb6ha4wJRmRsoKekRXRyvVPxKUiGkVGEFnfvswwXQMzRiiik4xYEpm+zHILDS4Wy8UFeE7jtfUK/i15Ea2seRB5uQeI0Bs/ew1mcWGw7kKkNjYrUj9aZP7m4o1Zzg1W512IOKVSEZUVufm+XyRu89dwOl/OmWQEdFbkHuD+gMgSNy+yNK+7EcllxLpUZEqXflbk3QIv+HdLc7FYvOlCxFkNuiWitc5dIx8AeU8iKSa8DHRBnd61NOREPoXm5wcRZmBGVJIRlRFZAawxKatbriK/efud+AtkisWkRyKZUwsVosjbKVMR91sZWQMyuW9c77vz1NAVlBGAY3etT9Dgcypy/mU2uz6DzsiLQCqyAs/NDXhWicjZ7Mt88fUaOoJOrWMZmQDEa2TDZFfk7uoO4GoGHUGf7PpIRlbQ4m32Yr+8hI4gETgi8g1arFKR8+uvl3fQFXT7PfKBOJ00uZlmRK5+zD5CJ1BGNBw+tfLALlezGjrgkZ8jKe18nAF8nGHRDfTf79+KzK7Pz7u+2J2Fg9fIbd5jCk2Wlyw+EA/etdbTnMfPNbQ56/5fFLVHpGf4jMDTEMl+r+VGvXqqsO8LOq1c1bPHCuWe736t6VdKdGXKVkbo3KpGJfQFbUeVs9mMqBJNxuPT8SnRbKS940MhcaOOXCgu9whoYTyw3nikIt7EOlONPNWorkeBUFe176lDGxuhDANYhMjQsymo8qMRf1gaQathSZ3bmCqO163p8LlufKybnlooosrSObMX95iBdOR4jHtEqEOPRIRyosLjfB/msLKhahYIFiECxzF486IOfPliU1Fo+ENiUSI0l2/EJeKiYeUQZ2NJK/mmRQ0EMiJqg03xevinwm4Thd1xI9R2YBtfKhqIsc3jFM2llI8uYwD2UMAGmlQhwSMRQVSfCBqpCOgNyuuEDaEq9oYOKg9BR+5O125ovTtCA1TRHKEH0EOnIqTixx8ARaXC2pcB5RsQ+o6zEwR4dLuNTZoqzrpdAFqRcS6gfJAIETUASIl2qBGrGA5JCNAOJKPUBiROQiHxXcBma8ydLpKIJMSc6WYrzkz7YY94eAeNYJonjEWzzHK0FwV20Nsh/T//FLBPiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S4ISLcGBZFz37Zn0cNi2djeALUL4pBUfc+J2qMGieD58O+UzwbnPwC9rQ9R9RHLAMAAAAASUVORK5CYII=", + "description": "Displays the number of alarms based on selected filter.", + "descriptor": { + "type": "latest", + "sizeX": 3.5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-alarm-count-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-alarm-count-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = Number((prevValue + Math.random() * 4 - 2).toFixed(0));\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Total\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"warning\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"range\",\"color\":\"rgba(0, 105, 92, 1)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"rgba(0, 105, 92, 1)\"},{\"from\":1,\"to\":null,\"color\":\"rgba(209, 39, 48, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Alarm count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}" + }, + "externalId": null +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/entity_count.json b/application/src/main/data/json/system/widget_types/entity_count.json new file mode 100644 index 0000000000..9efa02b2f6 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/entity_count.json @@ -0,0 +1,23 @@ +{ + "fqn": "entity_count", + "name": "Entity count", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAnFBMVEXg4ODf39/g4ODg4OAAAAD////9/f3g4ODxjRf7+/v6+vr19fX39/ft7e3z8/P5+fnx8fH2uG4hISH09PTk5OTv7+/51KhYWFisrKzLy8svLy+fn5/61Kg8PDyxsbGpqam6urqXl5fzmzSQkJCCgoJ0dHTc3NzV1dXDw8PHx8fylCX4xIhKSkrU1NT74MD1rFb98eKPj49mZmb+9/EJyyRgAAAABXRSTlPvIL+vAC9A4IoAAATwSURBVHja7ZyJctowEEBNkxX1ATbGYG4IIUBzND3+/9+6QkrWVHacpB13ne6TWVu33kgM08DUu+x88rpt56Jz6XW8kYKWoxLUuEjgAzDCY9X6/dAoz+vCh6ArIswQEW6ICDdEhBsiwg0R4YaIcENEuCEi3BARbogIN0SEGyLCDRHhhohwQ0S4ISLcEBFuiAg3RIQbIsINEeGGiHBDRLghItwQEW78HyIKamHzW9vfRFSbqBbBSt8PEB+TiefYWrxsJTXFOgy22pbQ3RbahsURC8GnsWk+Go6Kn+ZTFSKoEURRWMVwGL6PoZPDQJGoLHQ7I3HgK1Uu4seRz+bQ1+JHsTEhEfJojwaioqBCJPKhVeCCy0VCaBcqxC1xRfxgCC1jWCai/Lh9IrEropQf9cGyuP1cwnYBzOhHvlLujpDI9nMpt1BgP19PgVhB07gi7o58rgAKTKewOQJkPeiFkGGCbA8Q7XvQHEmFSPJGkXAOq+Nqf5ziwxVMV8cNzB/mIVTCVQRX/32zWofzhylcYYIs+76ZT6ExXBHkHSLZGq56vQhWa+2EW5H11jpfQ+M7MiiwdUWu1vMIjuvVA+xPIvvV6ohOTR8tUGciyhW5gwJ3RsQligrP5lVNAzuiwBFZfHWPFjNetyOL8dMH4Ri54ypS+x4hkQEsFl+hLSLwkgi+WiOi3iGSJHRvGBKBcxH1dpHDfZreZwBZnqZ5BsgkTyfQECTypzuSzZabySwHuEnNHa7TfJJBQ9DRqtuRu2/fxiceBzAeu2/2TfpFS0CS3miHA2TpNTQHiaiaHfkJlsFAR0ckybB5vjTr3+CZ2qWT3e6f74grsh1YtrePGB9JhJigRKKP1RxF8tksX84OUEPTR8vFFTnMfmDcpT9u0vQLimSQ4TlrDveTHXmHSLa8P/WY5LtdmuljBrDM4RWw+vcIeiwzsCzvAW5m2H9WJ8JvR7Jlej2ZTNDlyzyf6Vt6c9g1+0GCIvDie+S23GMLBK5boxeez/IDIPNlOruGGpo9WuNtmcftAmrIEqihGZHW/Z81WgQ+ikjp37Va9a0C0o9UmUgctuxrhSAs+9sv+G3bEhVGgbMj5myF/QDagvL7w9gv2REUCdBkNOqNekQx45aOXmpiLyooa4rT1VA+MXZMwsivEMHDhSqaYT9J+obEFCS6JDF5zJhoKjCYlqYEQ/Gmay26m9uCZtPRFlKXoa1PzobTXzFHgfZwjxacvmSP0QWTvohTWXi6m5vO2Ra2goKBss/9Timk0amTzTtDUFPieeIYPVwRRCE+EiBxHAcxRvOgA2ZNQKhCl9kXlfux7W6DzVFn268wVmBvNJQJuoCiKbF3H1EIuCKgTaoIMJVX2MutcB9trrJfUJjKhqByUGU1XJEnCk39KjN19qScyqpe6reuZzNQTpmMUpWTqhMVP+Fo129qtIa7I0WX1wn9VW14ey3ghVSI6FrTQp2S9dKpgBW20eZ1oEQPT42dZBeizKVoMpuzg9CMxRWRhitC0AqKOSeeD0UrKKyvMI6xsZLudAaSd5b07PE//xSwTYgIN0SEGyLCDRHhhohwQ0S4ISLcEBFuiAg3RIQbIsINEeGGiHBDRLghItwQEW6ICDdEhBsiwg0R4YaIcENEuCEi3Oh6Xqt+D1+F6nqfRvABSC68jpe0fk/UCDUuOxfdtuN96lz+Agb8xlnnx/XqAAAAAElFTkSuQmCC", + "description": "Displays the number of entities based on selected filter.", + "descriptor": { + "type": "latest", + "sizeX": 3.5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.countWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.countWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '220px',\n previewHeight: '100px',\n embedTitlePanel: true,\n hideDataSettings: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-entity-count-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-entity-count-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"count\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"return 150;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"],\"assignedToCurrentUser\":false,\"assigneeId\":null}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"showLabel\":true,\"label\":\"Devices\",\"labelFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.54)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":20,\"iconSizeUnit\":\"px\",\"icon\":\"devices\",\"iconColor\":{\"type\":\"constant\",\"color\":\"rgba(255, 255, 255, 1)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIconBackground\":true,\"iconBackgroundSize\":36,\"iconBackgroundSizeUnit\":\"px\",\"iconBackgroundColor\":{\"type\":\"constant\",\"color\":\"rgb(241, 141, 23)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showChevron\":false,\"chevronSize\":24,\"chevronSizeUnit\":\"px\",\"chevronColor\":\"rgba(0, 0, 0, 0.38)\",\"layout\":\"column\"},\"title\":\"Entity count\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":null,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.54)\"}" + }, + "externalId": null +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 8530478c2a..4bb3645f20 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -523,6 +523,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("entity_widgets"); this.deleteSystemWidgetBundle("html_widgets"); this.deleteSystemWidgetBundle("tables"); + this.deleteSystemWidgetBundle("count_widgets"); installScripts.loadSystemWidgets(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html new file mode 100644 index 0000000000..d43a067e3d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.html @@ -0,0 +1,61 @@ + + +
+
+
alarm.filter
+ +
+ +
+
+
widget-config.appearance
+ +
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts new file mode 100644 index 0000000000..782d2d4547 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarm-count-basic-config.component.ts @@ -0,0 +1,107 @@ +/// +/// Copyright © 2016-2023 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 { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DatasourceType, WidgetConfig, widgetType, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { getAlarmFilterConfig, setAlarmFilterConfig } from '@shared/models/widget-settings.models'; +import { UtilsService } from '@core/services/utils.service'; +import { AlarmSearchStatus } from '@shared/models/alarm.models'; +import { + countDefaultSettings, + CountWidgetSettings +} from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-alarm-count-basic-config', + templateUrl: './alarm-count-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class AlarmCountBasicConfigComponent extends BasicWidgetConfigComponent { + + alarmSearchStatus = AlarmSearchStatus; + + alarmCountWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private utils: UtilsService, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.alarmCountWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + let datasources = configData.config.datasources; + if (!datasources || !datasources.length) { + datasources = [{}]; + configData.config.datasources = datasources; + } + datasources[0].type = DatasourceType.alarmCount; + datasources[0].alarmFilterConfig = {statusList: [AlarmSearchStatus.ACTIVE]}; + datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)]; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: CountWidgetSettings = {...countDefaultSettings(true), ...(configData.config.settings || {})}; + this.alarmCountWidgetConfigForm = this.fb.group({ + alarmFilterConfig: [getAlarmFilterConfig(configData.config.datasources), []], + + settings: [settings, []], + + backgroundColor: [configData.config.backgroundColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setAlarmFilterConfig(config.alarmFilterConfig, this.widgetConfig.config.datasources); + + this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings}; + + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html index e343ac9b81..d2d9fc5e8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.html @@ -49,7 +49,7 @@ formControlName="columns">
-
widget-config.card-appearance
+
widget-config.appearance
{{ 'widget-config.card-title' | translate }} @@ -85,6 +85,29 @@
+
+
+
widgets.table.table-buttons
+
+ + {{ 'widgets.table.display-alarm-activity' | translate }} + + + {{ 'widgets.table.display-alarm-details' | translate }} + + + {{ 'widgets.table.allow-alarms-assign' | translate }} + + + {{ 'widgets.table.allow-alarms-ack' | translate }} + + + {{ 'widgets.table.allow-alarms-clear' | translate }} + +
+
+
+
widget-config.card-appearance
widget-config.show-card-buttons
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts index 6c25585f76..4f61aea583 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/alarm/alarms-table-basic-config.component.ts @@ -69,6 +69,13 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent showTitleIcon: [configData.config.showTitleIcon, []], titleIcon: [configData.config.titleIcon, []], iconColor: [configData.config.iconColor, []], + + displayActivity: [configData.config.settings?.displayActivity, []], + displayDetails: [configData.config.settings?.displayDetails, []], + allowAssign: [configData.config.settings?.allowAssign, []], + allowAcknowledgment: [configData.config.settings?.allowAcknowledgment, []], + allowClear: [configData.config.settings?.allowClear, []], + cardButtons: [this.getCardButtons(configData.config), []], color: [configData.config.color, []], backgroundColor: [configData.config.backgroundColor, []], @@ -84,7 +91,14 @@ export class AlarmsTableBasicConfigComponent extends BasicWidgetConfigComponent this.widgetConfig.config.actions = config.actions; this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + this.widgetConfig.config.settings.alarmsTitle = config.title; + this.widgetConfig.config.settings.displayActivity = config.displayActivity; + this.widgetConfig.config.settings.displayDetails = config.displayDetails; + this.widgetConfig.config.settings.allowAssign = config.allowAssign; + this.widgetConfig.config.settings.allowAcknowledgment = config.allowAcknowledgment; + this.widgetConfig.config.settings.allowClear = config.allowClear; + this.widgetConfig.config.titleFont = config.titleFont; this.widgetConfig.config.titleColor = config.titleColor; this.widgetConfig.config.showTitleIcon = config.showTitleIcon; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 7c4168a786..69500d1c85 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -27,7 +27,7 @@ import { } from '@home/components/widget/config/basic/common/widget-actions-panel.component'; import { EntitiesTableBasicConfigComponent -} from '@home/components/widget/config/basic/cards/entities-table-basic-config.component'; +} from '@home/components/widget/config/basic/entity/entities-table-basic-config.component'; import { DataKeysPanelComponent } from '@home/components/widget/config/basic/common/data-keys-panel.component'; import { DataKeyRowComponent } from '@home/components/widget/config/basic/common/data-key-row.component'; import { @@ -49,6 +49,12 @@ import { import { AggregatedDataKeysPanelComponent } from '@home/components/widget/config/basic/cards/aggregated-data-keys-panel.component'; +import { + AlarmCountBasicConfigComponent +} from '@home/components/widget/config/basic/alarm/alarm-count-basic-config.component'; +import { + EntityCountBasicConfigComponent +} from '@home/components/widget/config/basic/entity/entity-count-basic-config.component'; @NgModule({ declarations: [ @@ -63,7 +69,9 @@ import { AggregatedDataKeyRowComponent, AggregatedDataKeysPanelComponent, DataKeyRowComponent, - DataKeysPanelComponent + DataKeysPanelComponent, + AlarmCountBasicConfigComponent, + EntityCountBasicConfigComponent ], imports: [ CommonModule, @@ -82,7 +90,9 @@ import { AggregatedDataKeyRowComponent, AggregatedDataKeysPanelComponent, DataKeyRowComponent, - DataKeysPanelComponent + DataKeysPanelComponent, + AlarmCountBasicConfigComponent, + EntityCountBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -95,5 +105,7 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + +
+
widget-config.appearance
+ +
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts new file mode 100644 index 0000000000..c18153ac50 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entity-count-basic-config.component.ts @@ -0,0 +1,98 @@ +/// +/// Copyright © 2016-2023 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 { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DatasourceType, WidgetConfig, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { isUndefined } from '@core/utils'; +import { UtilsService } from '@core/services/utils.service'; +import { countDefaultSettings, CountWidgetSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-entity-count-basic-config', + templateUrl: './entity-count-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class EntityCountBasicConfigComponent extends BasicWidgetConfigComponent { + + entityCountWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private utils: UtilsService, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.entityCountWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + let datasources = configData.config.datasources; + if (!datasources || !datasources.length) { + datasources = [{}]; + configData.config.datasources = datasources; + } + datasources[0].type = DatasourceType.entityCount; + datasources[0].dataKeys = [this.utils.createKey({name: 'count'}, DataKeyType.count)]; + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: CountWidgetSettings = {...countDefaultSettings(false), ...(configData.config.settings || {})}; + this.entityCountWidgetConfigForm = this.fb.group({ + datasources: [configData.config.datasources, []], + settings: [settings, []], + + backgroundColor: [configData.config.backgroundColor, []], + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.settings = {...(this.widgetConfig.config.settings || {}), ...config.settings}; + + this.widgetConfig.config.backgroundColor = config.backgroundColor; + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html index 7f816e4593..a8c26dce3f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasource.component.html @@ -26,7 +26,7 @@
- + datasource.label @@ -54,7 +54,7 @@ formControlName="entityAliasId" [callbacks]="entityAliasSelectCallbacks"> -
{{ 'widget-config.timeseries-key-error' | translate }}
- {{ 'device.device' | translate }} {{ 'entity.entity-alias' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts index adc7eb1019..849283f8d2 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/datasources.component.ts @@ -93,6 +93,18 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid @Input() disabled: boolean; + @Input() + @coerceBoolean() + hideDatasourcesMode = false; + + @Input() + @coerceBoolean() + hideDatasourceLabel = false; + + @Input() + @coerceBoolean() + displayDatasourceFilterForBasicMode = false; + @Input() @coerceBoolean() hideDataKeyLabel = false; @@ -285,7 +297,8 @@ export class DatasourcesComponent implements ControlValueAccessor, OnInit, Valid if (datasources && datasources.length) { datasourcesMode = datasources[0].type; } - if (datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) { + if (!this.hideDatasourcesMode + && datasourcesMode !== DatasourceType.device && datasourcesMode !== DatasourceType.entity) { datasourcesMode = DatasourceType.device; } return datasourcesMode; 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/alarm/alarms-table-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.html 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/alarm/alarms-table-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.scss 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/alarm/alarms-table-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/alarms-table-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/alarm/alarms-table-widget.component.ts index 58c3804c19..034c131769 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/alarm/alarms-table-widget.component.ts @@ -149,7 +149,7 @@ interface AlarmWidgetActionDescriptor extends TableCellButtonActionDescriptor { @Component({ selector: 'tb-alarms-table-widget', templateUrl: './alarms-table-widget.component.html', - styleUrls: ['./alarms-table-widget.component.scss', './table-widget.scss'] + styleUrls: ['./alarms-table-widget.component.scss', './../table-widget.scss'] }) export class AlarmsTableWidgetComponent extends PageComponent implements OnInit, OnDestroy, AfterViewInit { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html new file mode 100644 index 0000000000..e99863e1a9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.html @@ -0,0 +1,37 @@ + +
+
+ +
+
+
+
+
+ {{ icon }} +
+
+
{{ label }}
+
+
{{ valueText }}
+
+
+
+ chevron_right +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss new file mode 100644 index 0000000000..8deb211897 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.scss @@ -0,0 +1,80 @@ +/** + * Copyright © 2016-2023 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-count-panel { + width: 100%; + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + padding: 12px; + &.tb-count-pointer { + cursor: pointer; + } + .tb-count-panel-column { + flex: 1; + display: flex; + flex-direction: column; + gap: 12px; + } + .tb-count-panel-row { + flex: 1; + display: flex; + flex-direction: row; + align-items: center; + gap: 12px; + } + .tb-count-icon-panel { + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + .mat-icon { + z-index: 1; + } + } + .tb-count-icon-background-panel { + position: absolute; + inset: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + .tb-count-label-value-panel { + flex: 1; + display: flex; + flex-direction: column; + place-content: flex-start space-around; + align-items: flex-start; + gap: 0; + &.tb-count-layout-row { + flex-direction: row; + align-items: center; + } + } + } +} + +:host ::ng-deep { + .tb-count-panel { + .tb-widget-title { + padding: 0; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts new file mode 100644 index 0000000000..8a8974c8bd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts @@ -0,0 +1,148 @@ +/// +/// Copyright © 2016-2023 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 { ChangeDetectorRef, Component, Input, OnInit, TemplateRef } from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { formatValue } from '@core/utils'; +import { + ColorProcessor, + ComponentStyle, + getSingleTsValue, + iconStyle, + textStyle +} from '@shared/models/widget-settings.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { + CountCardLayout, + countDefaultSettings, + CountWidgetSettings +} from '@home/components/widget/lib/count/count-widget.models'; +import { coerceBoolean } from '@shared/decorators/coercion'; + +@Component({ + selector: 'tb-count-widget', + templateUrl: './count-widget.component.html', + styleUrls: ['./count-widget.component.scss'] +}) +export class CountWidgetComponent implements OnInit { + + settings: CountWidgetSettings; + + countCardLayout = CountCardLayout; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + @coerceBoolean() + @Input() + alarmElseEntity: boolean; + + layout: CountCardLayout; + + showLabel = true; + label: string; + labelStyle: ComponentStyle = {}; + labelColor: ColorProcessor; + + showIcon = true; + icon = ''; + iconStyle: ComponentStyle = {}; + iconColor: ColorProcessor; + + showIconBackground = true; + iconBackgroundSize: string; + iconBackgroundStyle: ComponentStyle = {}; + iconBackgroundColor: ColorProcessor; + + valueText = 'N/A'; + valueStyle: ComponentStyle = {}; + valueColor: ColorProcessor; + + showChevron = false; + chevronStyle: ComponentStyle = {}; + + constructor(private widgetComponent: WidgetComponent, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.countWidget = this; + this.settings = {...countDefaultSettings(this.alarmElseEntity), ...this.ctx.settings}; + + this.layout = this.settings.layout; + + this.showLabel = this.settings.showLabel; + this.label = this.settings.label; + this.labelStyle = textStyle(this.settings.labelFont, '0.4px'); + this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); + + this.showIcon = this.settings.showIcon; + this.icon = this.settings.icon; + this.iconStyle = iconStyle(this.settings.iconSize, this.settings.iconSizeUnit); + this.iconColor = ColorProcessor.fromSettings(this.settings.iconColor); + + this.showIconBackground = this.settings.showIconBackground; + if (this.showIconBackground) { + this.iconBackgroundSize = this.settings.iconBackgroundSize + this.settings.iconBackgroundSizeUnit; + } else { + this.iconBackgroundSize = this.settings.iconSize + this.settings.iconSizeUnit; + } + this.iconBackgroundStyle = { + width: this.iconBackgroundSize, + height: this.iconBackgroundSize, + borderRadius: '4px' + }; + this.iconBackgroundColor = ColorProcessor.fromSettings(this.settings.iconBackgroundColor); + + this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); + + this.showChevron = this.settings.showChevron; + this.chevronStyle = iconStyle(this.settings.chevronSize, this.settings.chevronSizeUnit); + this.chevronStyle.color = this.settings.chevronColor; + } + + public onInit() { + } + + public onDataUpdated() { + const tsValue = getSingleTsValue(this.ctx.data); + let value: any; + if (tsValue) { + value = tsValue[1]; + this.valueText = formatValue(value, 0); + } else { + this.valueText = 'N/A'; + } + this.labelColor.update(value); + this.iconColor.update(value); + this.iconBackgroundColor.update(value); + this.valueColor.update(value); + this.cd.detectChanges(); + } + + public cardClick($event: Event) { + const descriptors = this.ctx.actionsApi.getActionDescriptors('cardClick'); + if (descriptors.length) { + $event.stopPropagation(); + const descriptor = descriptors[0]; + this.ctx.actionsApi.handleWidgetAction($event, descriptor); + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts new file mode 100644 index 0000000000..4a1b307f4b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.models.ts @@ -0,0 +1,122 @@ +/// +/// Copyright © 2016-2023 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 { + ColorSettings, + ColorType, + constantColor, + cssUnit, + defaultColorFunction, + Font +} from '@shared/models/widget-settings.models'; + +export enum CountCardLayout { + column = 'column', + row = 'row' +} + +export const countCardLayouts = Object.keys(CountCardLayout) as CountCardLayout[]; + +export const countCardLayoutTranslations = new Map( + [ + [CountCardLayout.column, 'widgets.count.layout-column'], + [CountCardLayout.row, 'widgets.count.layout-row'] + ] +); + +export const alarmCountCardLayoutImages = new Map( + [ + [CountCardLayout.column, 'assets/widget/alarm-count/column-layout.svg'], + [CountCardLayout.row, 'assets/widget/alarm-count/row-layout.svg'] + ] +); + +export const entityCountCardLayoutImages = new Map( + [ + [CountCardLayout.column, 'assets/widget/entity-count/column-layout.svg'], + [CountCardLayout.row, 'assets/widget/entity-count/row-layout.svg'] + ] +); + +export interface CountWidgetSettings { + layout: CountCardLayout; + showLabel: boolean; + label: string; + labelFont: Font; + labelColor: ColorSettings; + showIcon: boolean; + icon: string; + iconSize: number; + iconSizeUnit: cssUnit; + iconColor: ColorSettings; + showIconBackground: boolean; + iconBackgroundSize: number; + iconBackgroundSizeUnit: cssUnit; + iconBackgroundColor: ColorSettings; + valueFont: Font; + valueColor: ColorSettings; + showChevron: boolean; + chevronSize: number; + chevronSizeUnit: cssUnit; + chevronColor: string; +} + +export const countDefaultSettings = (alarmElseEntity: boolean): CountWidgetSettings => ({ + layout: CountCardLayout.column, + showLabel: true, + label: alarmElseEntity ? 'Total' : 'Devices', + labelFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '16px' + }, + labelColor: constantColor('rgba(0, 0, 0, 0.54)'), + showIcon: true, + icon: alarmElseEntity ? 'warning' : 'devices', + iconSize: 20, + iconSizeUnit: 'px', + iconColor: constantColor('rgba(255, 255, 255, 1)'), + showIconBackground: true, + iconBackgroundSize: 36, + iconBackgroundSizeUnit: 'px', + iconBackgroundColor: alarmElseEntity + ? { + color: 'rgba(0, 105, 92, 1)', + type: ColorType.range, + rangeList: [ + {from: 0, to: 0, color: 'rgba(0, 105, 92, 1)'}, + {from: 1, color: 'rgba(209, 39, 48, 1)'} + ], + colorFunction: defaultColorFunction + } + : constantColor('rgba(241, 141, 23, 1)'), + valueFont: { + family: 'Roboto', + size: 20, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '24px' + }, + valueColor: constantColor('rgba(0, 0, 0, 0.87)'), + showChevron: false, + chevronSize: 24, + chevronSizeUnit: 'px', + chevronColor: 'rgba(0, 0, 0, 0.38)' +}); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.scss diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts index 75ea8657d7..17e95601c1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.component.ts @@ -64,7 +64,7 @@ import { NodeRelationQueryFunction, NodesSortFunction, NodeTextFunction -} from '@home/components/widget/lib/entities-hierarchy-widget.models'; +} from '@home/components/widget/lib/entity/entities-hierarchy-widget.models'; import { EntityRelationsQuery } from '@shared/models/relation.models'; import { AliasFilterType, RelationsQueryFilter } from '@shared/models/alias.models'; import { EntityFilter } from '@shared/models/query/query.models'; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-hierarchy-widget.models.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-hierarchy-widget.models.ts 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/entity/entities-table-widget.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.html 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/entity/entities-table-widget.component.scss similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.scss rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.scss 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/entity/entities-table-widget.component.ts similarity index 99% rename from ui-ngx/src/app/modules/home/components/widget/lib/entities-table-widget.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/entity/entities-table-widget.component.ts index 1428b16f17..df71fce4f8 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/entity/entities-table-widget.component.ts @@ -121,7 +121,7 @@ interface EntitiesTableWidgetSettings extends TableWidgetSettings { @Component({ selector: 'tb-entities-table-widget', templateUrl: './entities-table-widget.component.html', - styleUrls: ['./entities-table-widget.component.scss', './table-widget.scss'] + styleUrls: ['./entities-table-widget.component.scss', './../table-widget.scss'] }) export class EntitiesTableWidgetComponent extends PageComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html new file mode 100644 index 0000000000..ab8e7635dd --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.html @@ -0,0 +1,23 @@ + + +
+
widgets.alarm-count.alarm-count-card-style
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts new file mode 100644 index 0000000000..6a36891c7e --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component.ts @@ -0,0 +1,62 @@ +/// +/// Copyright © 2016-2023 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-alarm-count-widget-settings', + templateUrl: './alarm-count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'] +}) +export class AlarmCountWidgetSettingsComponent extends WidgetSettingsComponent { + + alarmCountWidgetSettingsForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.alarmCountWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...countDefaultSettings(true)}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.alarmCountWidgetSettingsForm = this.fb.group({ + alarmCountSettings: [settings.alarmCountSettings, []], + }); + } + + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + alarmCountSettings: settings + }; + } + + protected prepareOutputSettings(settings: any): WidgetSettings { + return settings.alarmCountSettings; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts index 223cf93e77..fff6e2c8fc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component.ts @@ -53,6 +53,7 @@ export class AlarmsTableWidgetSettingsComponent extends WidgetSettingsComponent allowAcknowledgment: true, allowClear: true, allowAssign: true, + displayActivity: true, displayPagination: true, defaultPageSize: 10, defaultSortOrder: '-createdTime', diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html new file mode 100644 index 0000000000..e373acb8a5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.html @@ -0,0 +1,103 @@ + + + + + {{ countCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.count.label' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.count.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.count.icon-background' | translate }} + +
+ + + + + + +
+
+
+
widgets.count.value
+
+ + + + +
+
+
+ + {{ 'widgets.count.chevron' | translate }} + +
+ + + + + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts new file mode 100644 index 0000000000..2a37a46d5c --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/count-widget-settings.component.ts @@ -0,0 +1,201 @@ +/// +/// Copyright © 2016-2023 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 { + AbstractControl, + ControlValueAccessor, + NG_VALUE_ACCESSOR, + UntypedFormBuilder, + UntypedFormGroup, + Validators +} from '@angular/forms'; +import {Store} from '@ngrx/store'; +import {AppState} from '@core/core.state'; +import { + alarmCountCardLayoutImages, + CountCardLayout, + countCardLayouts, + countCardLayoutTranslations, + CountWidgetSettings, entityCountCardLayoutImages +} from '@home/components/widget/lib/count/count-widget.models'; +import {PageComponent} from '@shared/components/page.component'; +import {Component, forwardRef, Input, OnInit} from '@angular/core'; +import { coerceBoolean } from '@shared/decorators/coercion'; +import { + valueCardLayoutImages, + valueCardLayoutTranslations +} from '@home/components/widget/lib/cards/value-card-widget.models'; + +@Component({ + selector: 'tb-count-widget-settings', + templateUrl: './count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'], + providers: [ + { + provide: NG_VALUE_ACCESSOR, + useExisting: forwardRef(() => CountWidgetSettingsComponent), + multi: true + } + ] +}) +export class CountWidgetSettingsComponent extends PageComponent implements OnInit, ControlValueAccessor { + + @Input() + disabled: boolean; + + @coerceBoolean() + @Input() + alarmElseEntity: boolean; + + private propagateChange = null; + + countCardLayouts = countCardLayouts; + + countCardLayoutTranslationMap = countCardLayoutTranslations; + countCardLayoutImageMap: Map; + + countWidgetConfigForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + ngOnInit(): void { + this.countCardLayoutImageMap = this.alarmElseEntity ? alarmCountCardLayoutImages : entityCountCardLayoutImages; + this.countWidgetConfigForm = this.fb.group({ + layout: [null, []], + showLabel: [null, []], + label: [null, []], + labelFont: [null, []], + labelColor: [null, []], + + showIcon: [null, []], + iconSize: [null, [Validators.min(0)]], + iconSizeUnit: [null, []], + icon: [null, []], + iconColor: [null, []], + + showIconBackground: [null, []], + iconBackgroundSize: [null, [Validators.min(0)]], + iconBackgroundSizeUnit: [null, []], + iconBackgroundColor: [null, []], + + valueFont: [null, []], + valueColor: [null, []], + + showChevron: [null, []], + chevronSize: [null, [Validators.min(0)]], + chevronSizeUnit: [null, []], + chevronColor: [null, []], + }); + this.countWidgetConfigForm.valueChanges.subscribe(() => { + this.updateModel(); + }); + for (const trigger of ['showLabel', 'showIcon', 'showIconBackground', 'showChevron']) { + const path = trigger.split('.'); + let control: AbstractControl = this.countWidgetConfigForm; + for (const part of path) { + control = this.countWidgetConfigForm.get(part); + } + control.valueChanges.subscribe(() => { + this.updateValidators(); + }); + } + } + + registerOnChange(fn: any): void { + this.propagateChange = fn; + } + + registerOnTouched(fn: any): void { + } + + + setDisabledState(isDisabled: boolean): void { + this.disabled = isDisabled; + if (isDisabled) { + this.countWidgetConfigForm.disable({emitEvent: false}); + } else { + this.countWidgetConfigForm.enable({emitEvent: false}); + this.updateValidators(); + } + } + + writeValue(value: CountWidgetSettings): void { + this.countWidgetConfigForm.patchValue( + value, {emitEvent: false} + ); + this.updateValidators(); + } + + private updateModel() { + const value: CountWidgetSettings = this.countWidgetConfigForm.value; + this.propagateChange(value); + } + + protected updateValidators() { + const showLabel: boolean = this.countWidgetConfigForm.get('showLabel').value; + const showIcon: boolean = this.countWidgetConfigForm.get('showIcon').value; + const showIconBackground: boolean = this.countWidgetConfigForm.get('showIconBackground').value; + const showChevron: boolean = this.countWidgetConfigForm.get('showChevron').value; + + if (showLabel) { + this.countWidgetConfigForm.get('label').enable({emitEvent: false}); + this.countWidgetConfigForm.get('labelFont').enable({emitEvent: false}); + this.countWidgetConfigForm.get('labelColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('label').disable({emitEvent: false}); + this.countWidgetConfigForm.get('labelFont').disable({emitEvent: false}); + this.countWidgetConfigForm.get('labelColor').disable({emitEvent: false}); + } + + if (showIcon) { + this.countWidgetConfigForm.get('iconSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('icon').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('iconSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('icon').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconColor').disable({emitEvent: false}); + } + + if (showIconBackground) { + this.countWidgetConfigForm.get('iconBackgroundSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('iconBackgroundSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('iconBackgroundColor').disable({emitEvent: false}); + } + + if (showChevron) { + this.countWidgetConfigForm.get('chevronSize').enable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronSizeUnit').enable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronColor').enable({emitEvent: false}); + } else { + this.countWidgetConfigForm.get('chevronSize').disable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronSizeUnit').disable({emitEvent: false}); + this.countWidgetConfigForm.get('chevronColor').disable({emitEvent: false}); + } + } + + protected readonly valueCardLayoutTranslations = valueCardLayoutTranslations; + protected readonly valueCardLayoutImages = valueCardLayoutImages; +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts index 6c383062ae..5a2a91b56b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts @@ -40,6 +40,9 @@ import { BackgroundSettingsComponent } from '@home/components/widget/lib/setting import { BackgroundSettingsPanelComponent } from '@home/components/widget/lib/settings/common/background-settings-panel.component'; +import { + CountWidgetSettingsComponent +} from "@home/components/widget/lib/settings/common/count-widget-settings.component"; @NgModule({ declarations: [ @@ -56,7 +59,8 @@ import { BackgroundSettingsPanelComponent, ValueSourceComponent, LegendConfigComponent, - WidgetFontComponent + WidgetFontComponent, + CountWidgetSettingsComponent ], imports: [ CommonModule, @@ -77,7 +81,8 @@ import { BackgroundSettingsPanelComponent, ValueSourceComponent, LegendConfigComponent, - WidgetFontComponent + WidgetFontComponent, + CountWidgetSettingsComponent ] }) export class WidgetSettingsCommonModule { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-key-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-key-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.html rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.html diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts similarity index 100% rename from ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/entities-table-widget-settings.component.ts rename to ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entities-table-widget-settings.component.ts diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html new file mode 100644 index 0000000000..e38fab6e27 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.html @@ -0,0 +1,23 @@ + + +
+
widgets.entity-count.entity-count-card-style
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts new file mode 100644 index 0000000000..348c893316 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/entity/entity-count-widget-settings.component.ts @@ -0,0 +1,62 @@ +/// +/// Copyright © 2016-2023 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 { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { countDefaultSettings } from '@home/components/widget/lib/count/count-widget.models'; + +@Component({ + selector: 'tb-entity-count-widget-settings', + templateUrl: './entity-count-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'] +}) +export class EntityCountWidgetSettingsComponent extends WidgetSettingsComponent { + + entityCountWidgetSettingsForm: UntypedFormGroup; + + constructor(protected store: Store, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.entityCountWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...countDefaultSettings(false)}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.entityCountWidgetSettingsForm = this.fb.group({ + entityCountSettings: [settings.entityCountSettings, []], + }); + } + + protected prepareInputSettings(settings: WidgetSettings): WidgetSettings { + return { + entityCountSettings: settings + }; + } + + protected prepareOutputSettings(settings: any): WidgetSettings { + return settings.entityCountSettings; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index e4ca0eb4d4..622f5a0c2a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -42,16 +42,16 @@ import { } from '@home/components/widget/lib/settings/cards/dashboard-state-widget-settings.component'; import { EntitiesHierarchyWidgetSettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-hierarchy-widget-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-hierarchy-widget-settings.component'; import { HtmlCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/html-card-widget-settings.component'; import { EntitiesTableWidgetSettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-table-widget-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-table-widget-settings.component'; import { EntitiesTableKeySettingsComponent -} from '@home/components/widget/lib/settings/cards/entities-table-key-settings.component'; +} from '@home/components/widget/lib/settings/entity/entities-table-key-settings.component'; import { AlarmsTableWidgetSettingsComponent } from '@home/components/widget/lib/settings/alarm/alarms-table-widget-settings.component'; @@ -279,6 +279,12 @@ import { import { AggregatedValueCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/aggregated-value-card-widget-settings.component'; +import { + AlarmCountWidgetSettingsComponent +} from '@home/components/widget/lib/settings/alarm/alarm-count-widget-settings.component'; +import { + EntityCountWidgetSettingsComponent +} from '@home/components/widget/lib/settings/entity/entity-count-widget-settings.component'; @NgModule({ declarations: [ @@ -382,7 +388,9 @@ import { QuickLinksWidgetSettingsComponent, ValueCardWidgetSettingsComponent, AggregatedValueCardKeySettingsComponent, - AggregatedValueCardWidgetSettingsComponent + AggregatedValueCardWidgetSettingsComponent, + AlarmCountWidgetSettingsComponent, + EntityCountWidgetSettingsComponent ], imports: [ CommonModule, @@ -491,7 +499,9 @@ import { QuickLinksWidgetSettingsComponent, ValueCardWidgetSettingsComponent, AggregatedValueCardKeySettingsComponent, - AggregatedValueCardWidgetSettingsComponent + AggregatedValueCardWidgetSettingsComponent, + AlarmCountWidgetSettingsComponent, + EntityCountWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -565,5 +575,7 @@ export const widgetSettingsComponentsMap: {[key: string]: Type diff --git a/ui-ngx/src/app/shared/components/material-icon-select.component.ts b/ui-ngx/src/app/shared/components/material-icon-select.component.ts index 255aeb0668..a7af6eaa70 100644 --- a/ui-ngx/src/app/shared/components/material-icon-select.component.ts +++ b/ui-ngx/src/app/shared/components/material-icon-select.component.ts @@ -51,6 +51,9 @@ export class MaterialIconSelectComponent extends PageComponent implements OnInit @Input() color: string; + @Input() + backgroundColor: string; + @Input() disabled: boolean; diff --git a/ui-ngx/src/app/shared/models/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts index 4bba815a37..2769a635e4 100644 --- a/ui-ngx/src/app/shared/models/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -20,6 +20,8 @@ import { Injector } from '@angular/core'; import { DatePipe } from '@angular/common'; import { DateAgoPipe } from '@shared/pipe/date-ago.pipe'; import { TranslateService } from '@ngx-translate/core'; +import { AlarmFilterConfig } from '@shared/models/query/query.models'; +import { AlarmSearchStatus } from '@shared/models/alarm.models'; export type ComponentStyle = {[klass: string]: any}; @@ -111,13 +113,15 @@ export const defaultTimewindowStyle: TimewindowStyle = { export const constantColor = (color: string): ColorSettings => ({ type: ColorType.constant, color, - colorFunction: 'var temperature = value;\n' + + colorFunction: defaultColorFunction +}); + +export const defaultColorFunction = 'var temperature = value;\n' + 'if (typeof temperature !== undefined) {\n' + ' var percent = (temperature + 60)/120 * 100;\n' + ' return tinycolor.mix(\'blue\', \'red\', percent).toHexString();\n' + '}\n' + - 'return \'blue\';' -}); + 'return \'blue\';'; export const cssSizeToStrSize = (size?: number, unit?: cssUnit): string => (isDefinedAndNotNull(size) ? size + '' : '0') + (unit || 'px'); @@ -422,6 +426,22 @@ export const getDataKey = (datasources?: Datasource[]): DataKey => { return null; }; +export const getAlarmFilterConfig = (datasources?: Datasource[]): AlarmFilterConfig => { + if (datasources && datasources.length) { + const config = datasources[0].alarmFilterConfig; + if (config) { + return config; + } + } + return { statusList: [ AlarmSearchStatus.ACTIVE ] }; +}; + +export const setAlarmFilterConfig = (config: AlarmFilterConfig, datasources?: Datasource[]): void => { + if (datasources && datasources.length) { + datasources[0].alarmFilterConfig = config; + } +}; + export const getLabel = (datasources?: Datasource[]): string => { const dataKey = getDataKey(datasources); if (dataKey) { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index c04eb6f7ec..a08d8837f5 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -179,6 +179,7 @@ export interface WidgetTypeParameters { previewWidth?: string; previewHeight?: string; embedTitlePanel?: boolean; + hideDataSettings?: boolean; } export interface WidgetControllerDescriptor { 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 6ed0b5fde5..8a93e1bbfd 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -6084,6 +6084,22 @@ "aggregation": "Aggregation", "aggregated-value-card-style": "Aggregated value card style" }, + "alarm-count": { + "alarm-count-card-style": "Alarm count card style" + }, + "entity-count": { + "entity-count-card-style": "Entity count card style" + }, + "count": { + "layout": "Layout", + "layout-column": "Column", + "layout-row": "Row", + "label": "Label", + "icon": "Icon", + "icon-background": "Icon background", + "value": "Value", + "chevron": "Chevron" + }, "table": { "common-table-settings": "Common Table Settings", "enable-search": "Enable search", @@ -6403,7 +6419,8 @@ "element-click": "On HTML element click", "pie-slice-click": "On slice click", "row-double-click": "On row double click", - "action-button-click": "Action button click" + "action-button-click": "Action button click", + "card-click": "On card click" } }, "paginator" : { diff --git a/ui-ngx/src/assets/widget/alarm-count/column-layout.svg b/ui-ngx/src/assets/widget/alarm-count/column-layout.svg new file mode 100644 index 0000000000..d797417a65 --- /dev/null +++ b/ui-ngx/src/assets/widget/alarm-count/column-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/alarm-count/row-layout.svg b/ui-ngx/src/assets/widget/alarm-count/row-layout.svg new file mode 100644 index 0000000000..2519f5c411 --- /dev/null +++ b/ui-ngx/src/assets/widget/alarm-count/row-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/entity-count/column-layout.svg b/ui-ngx/src/assets/widget/entity-count/column-layout.svg new file mode 100644 index 0000000000..44cab51f33 --- /dev/null +++ b/ui-ngx/src/assets/widget/entity-count/column-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/entity-count/row-layout.svg b/ui-ngx/src/assets/widget/entity-count/row-layout.svg new file mode 100644 index 0000000000..06a5778426 --- /dev/null +++ b/ui-ngx/src/assets/widget/entity-count/row-layout.svg @@ -0,0 +1,21 @@ + + + + + + + + + + + + + + + + + + + + + From 02390460464401734a6b564adfc28563bd918593 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 15 Sep 2023 09:56:48 +0300 Subject: [PATCH 054/267] Edge instructions code wrapper style updated --- .../edge-instructions-dialog.component.scss | 31 ++++++++++++++++--- 1 file changed, 27 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index a22671248a..092f3c6408 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -14,8 +14,11 @@ * limitations under the License. */ +@use '@angular/material' as mat; @import "../../../../../scss/constants"; +@import '../theme.scss'; +$tb-primary: mat.get-color-from-palette($tb-primary); :host { height: 100%; max-height: 100vh; @@ -63,7 +66,8 @@ .mat-mdc-dialog-content { max-height: 80vh; - padding: 16px; + padding: 0 16px 16px 16px; + border-top: 16px solid #fff; } } @@ -73,10 +77,10 @@ div.code-wrapper button.clipboard-btn { right: -2px !important; p { - color: #305680; + color: $tb-primary !important; } p, div { - background-color: #F3F6FA; + background-color: unset !important; } div { img { @@ -88,11 +92,17 @@ display: block; width: 18px; height: 18px; - background: #305680; + background: $tb-primary; mask-image: url(/assets/copy-code-icon.svg); mask-repeat: no-repeat; } } + a { + color: $tb-primary; + &:hover { + color: $tb-primary; + } + } &.multiline { right: -2px !important; } @@ -101,6 +111,12 @@ padding-right: unset !important; padding-left: unset !important; } + pre[class*="language-"] { + border: 1px solid $tb-primary !important; + } + div { + background-color: #F3F6FA; + } } .mdc-button__label > span { .mat-icon { @@ -109,6 +125,13 @@ } } + .mat-mdc-tab-header { + position: sticky; + top: 0; + z-index: 10; + background-color: #fff; + } + .tabs-icon { margin-right: 8px; } From 4fbc6e7f203221d8b3915575fd6b5d422ebc074e Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 15 Sep 2023 10:44:37 +0300 Subject: [PATCH 055/267] UI: Remove initial name from datasources --- ui-ngx/src/app/core/services/dashboard-utils.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/core/services/dashboard-utils.service.ts b/ui-ngx/src/app/core/services/dashboard-utils.service.ts index bb4c738516..0e8cba3f80 100644 --- a/ui-ngx/src/app/core/services/dashboard-utils.service.ts +++ b/ui-ngx/src/app/core/services/dashboard-utils.service.ts @@ -397,6 +397,7 @@ export class DashboardUtilsService { const newDatasource = deepClone(datasource); if (newDatasource.type === DatasourceType.function) { newDatasource.type = DatasourceType.entity; + newDatasource.name = ''; if (widgetTypeDescriptor.hasBasicMode && config.configMode === WidgetConfigMode.basic) { newDatasource.type = DatasourceType.device; } From c450ced074698dee4fd061de9e93047a6de570f0 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 15 Sep 2023 13:11:07 +0300 Subject: [PATCH 056/267] UI: Added client/server/shared attribute to key filter --- .../home/components/filter/key-filter-dialog.component.ts | 3 ++- ui-ngx/src/app/shared/models/query/query.models.ts | 5 ++++- ui-ngx/src/assets/locale/locale.constant-en_US.json | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) 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 d8b1a21f6a..b210605d95 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 @@ -70,7 +70,8 @@ export class KeyFilterDialogComponent extends entityKeyTypes = this.data.telemetryKeysOnly ? [EntityKeyType.ATTRIBUTE, EntityKeyType.TIME_SERIES, EntityKeyType.CONSTANT] : - [EntityKeyType.ENTITY_FIELD, EntityKeyType.ATTRIBUTE, EntityKeyType.TIME_SERIES]; + [EntityKeyType.ENTITY_FIELD, EntityKeyType.ATTRIBUTE, EntityKeyType.CLIENT_ATTRIBUTE, + EntityKeyType.SERVER_ATTRIBUTE, EntityKeyType.SHARED_ATTRIBUTE, EntityKeyType.TIME_SERIES]; entityKeyTypeTranslations = entityKeyTypeTranslationMap; 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 5e4e7b3527..696ce5c3fb 100644 --- a/ui-ngx/src/app/shared/models/query/query.models.ts +++ b/ui-ngx/src/app/shared/models/query/query.models.ts @@ -54,7 +54,10 @@ export const entityKeyTypeTranslationMap = new Map( [EntityKeyType.ATTRIBUTE, 'filter.key-type.attribute'], [EntityKeyType.TIME_SERIES, 'filter.key-type.timeseries'], [EntityKeyType.ENTITY_FIELD, 'filter.key-type.entity-field'], - [EntityKeyType.CONSTANT, 'filter.key-type.constant'] + [EntityKeyType.CONSTANT, 'filter.key-type.constant'], + [EntityKeyType.CLIENT_ATTRIBUTE, 'filter.key-type.client-attribute'], + [EntityKeyType.SERVER_ATTRIBUTE, 'filter.key-type.server-attribute'], + [EntityKeyType.SHARED_ATTRIBUTE, 'filter.key-type.shared-attribute'] ] ); 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 76c30d46ae..cfae20cbe4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2595,7 +2595,10 @@ "attribute": "Attribute", "timeseries": "Timeseries", "entity-field": "Entity field", - "constant": "Constant" + "constant": "Constant", + "client-attribute": "Client attribute", + "server-attribute": "Server attribute", + "shared-attribute": "Shared attribute" }, "value-type": { "value-type": "Value type", From fe8aaaa4d9fad48b3ba6081709a02a1a4269bdee Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 15 Sep 2023 14:15:49 +0300 Subject: [PATCH 057/267] Fix HashPartitionServiceTest.testPartitionChangeEvents_isolatedProfile_oneCommonServer_oneDedicated --- .../server/queue/discovery/HashPartitionServiceTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java index 49008ab559..ef87794d96 100644 --- a/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/queue/discovery/HashPartitionServiceTest.java @@ -338,7 +338,6 @@ public class HashPartitionServiceTest { .setQueueName(isolatedQueue.getName()) .build(); partitionService_dedicated.removeQueue(queueDeleteMsg); - partitionService_dedicated.recalculatePartitions(dedicatedRuleEngine, List.of(commonRuleEngine)); verifyPartitionChangeEvent(event -> { QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, DataConstants.MAIN_QUEUE_NAME, tenantId); return event.getPartitionsMap().get(queueKey).isEmpty(); From 16e3a6e177b6ba766ee3b5bd3d0a0651cf5a704c Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 15 Sep 2023 16:39:58 +0300 Subject: [PATCH 058/267] edge tests stability: seq_id column - remove maxvalue. increased timeout for waiting on edge imitator respones --- .../java/org/thingsboard/server/edge/AssetEdgeTest.java | 6 +++--- .../java/org/thingsboard/server/edge/CustomerEdgeTest.java | 2 +- .../java/org/thingsboard/server/edge/DashboardEdgeTest.java | 2 +- .../java/org/thingsboard/server/edge/DeviceEdgeTest.java | 2 +- .../src/test/java/org/thingsboard/server/edge/EdgeTest.java | 2 +- .../org/thingsboard/server/edge/EntityViewEdgeTest.java | 2 +- .../java/org/thingsboard/server/edge/RuleChainEdgeTest.java | 2 +- .../java/org/thingsboard/server/edge/TelemetryEdgeTest.java | 4 ++++ .../test/java/org/thingsboard/server/edge/UserEdgeTest.java | 2 +- .../org/thingsboard/server/edge/imitator/EdgeImitator.java | 1 + application/src/test/resources/application-test.properties | 2 -- dao/src/test/resources/sql/system-test-psql.sql | 5 +---- 12 files changed, 16 insertions(+), 16 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java index faf0896b81..08ea322cb8 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AssetEdgeTest.java @@ -96,7 +96,7 @@ public class AssetEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/asset/" + savedAsset.getUuidId()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); // create asset #2 and assign to edge edgeImitator.expectMessageAmount(2); @@ -262,9 +262,9 @@ public class AssetEdgeTest extends AbstractEdgeTest { private Asset saveAssetOnCloudAndVerifyDeliveryToEdge() throws Exception { // create asset and assign to edge Asset savedAsset = saveAsset(StringUtils.randomAlphanumeric(15)); - edgeImitator.expectMessageAmount(1); // asset message + edgeImitator.expectMessageAmount(2); // asset and asset profile messages doPost("/api/edge/" + edge.getUuidId() - + "/asset/" + savedAsset.getUuidId(), Device.class); + + "/asset/" + savedAsset.getUuidId(), Asset.class); Assert.assertTrue(edgeImitator.waitForMessages()); Optional assetUpdateMsgOpt = edgeImitator.findMessageByType(AssetUpdateMsg.class); Assert.assertTrue(assetUpdateMsgOpt.isPresent()); diff --git a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java index 251b4b4caf..6cc15837d9 100644 --- a/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/CustomerEdgeTest.java @@ -42,7 +42,7 @@ public class CustomerEdgeTest extends AbstractEdgeTest { Customer customer = new Customer(); customer.setTitle("Edge Customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertFalse(edgeImitator.waitForMessages(5)); // assign edge to customer edgeImitator.expectMessageAmount(2); diff --git a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java index 2d21d30174..6180ced49c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DashboardEdgeTest.java @@ -99,7 +99,7 @@ public class DashboardEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/dashboard/" + savedDashboard.getUuidId()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); // create dashboard #2 and assign to edge edgeImitator.expectMessageAmount(1); diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java index 15b15c0be0..aed99b4cba 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java @@ -106,7 +106,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/device/" + savedDevice.getUuidId()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); // create device #2 and assign to edge edgeImitator.expectMessageAmount(2); diff --git a/application/src/test/java/org/thingsboard/server/edge/EdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/EdgeTest.java index 1f205af53a..fd34b0d973 100644 --- a/application/src/test/java/org/thingsboard/server/edge/EdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/EdgeTest.java @@ -39,7 +39,7 @@ public class EdgeTest extends AbstractEdgeTest { Customer customer = new Customer(); customer.setTitle("Edge Customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertFalse(edgeImitator.waitForMessages(5)); // assign edge to customer edgeImitator.expectMessageAmount(2); diff --git a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java index 470fd8e576..d56ded7014 100644 --- a/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/EntityViewEdgeTest.java @@ -105,7 +105,7 @@ public class EntityViewEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/entityView/" + savedEntityView.getUuidId()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); // create entity view #2 and assign to edge edgeImitator.expectMessageAmount(1); diff --git a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java index 228a85fc91..848b115c72 100644 --- a/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/RuleChainEdgeTest.java @@ -229,6 +229,6 @@ public class RuleChainEdgeTest extends AbstractEdgeTest { edgeImitator.expectMessageAmount(1); doDelete("/api/ruleChain/" + savedRuleChain.getUuidId()) .andExpect(status().isOk()); - Assert.assertTrue(edgeImitator.waitForMessages(1)); + Assert.assertTrue(edgeImitator.waitForMessages(5)); } } diff --git a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java index 2ee267b88c..922475f305 100644 --- a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java @@ -22,6 +22,7 @@ import com.google.protobuf.AbstractMessage; import org.awaitility.Awaitility; import org.junit.Assert; import org.junit.Test; +import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; @@ -41,6 +42,9 @@ import java.util.List; import java.util.concurrent.TimeUnit; @DaoSqlTest +@TestPropertySource(properties = { + "edges.storage.sleep_between_batches=1000" +}) public class TelemetryEdgeTest extends AbstractEdgeTest { @Test diff --git a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java index d1d555f691..3fd39328d5 100644 --- a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java @@ -120,7 +120,7 @@ public class UserEdgeTest extends AbstractEdgeTest { Customer customer = new Customer(); customer.setTitle("Edge Customer"); Customer savedCustomer = doPost("/api/customer", customer, Customer.class); - Assert.assertFalse(edgeImitator.waitForMessages(1)); + Assert.assertFalse(edgeImitator.waitForMessages(5)); // assign edge to customer edgeImitator.expectMessageAmount(2); 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 9425001aac..f9efbb3ee1 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 @@ -173,6 +173,7 @@ public class EdgeImitator { } private ListenableFuture> processDownlinkMsg(DownlinkMsg downlinkMsg) { + log.trace("processDownlinkMsg: {}", downlinkMsg); List> result = new ArrayList<>(); if (downlinkMsg.getAdminSettingsUpdateMsgCount() > 0) { for (AdminSettingsUpdateMsg adminSettingsUpdateMsg : downlinkMsg.getAdminSettingsUpdateMsgList()) { diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index a964b0b700..d8943b47e9 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -11,8 +11,6 @@ transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials # Edge disabled to speed up the context init. Will be enabled by @TestPropertySource in respective tests edges.enabled=false -edges.storage.no_read_records_sleep=500 -edges.storage.sleep_between_batches=500 actors.rpc.submit_strategy=BURST queue.rule-engine.stats.enabled=true diff --git a/dao/src/test/resources/sql/system-test-psql.sql b/dao/src/test/resources/sql/system-test-psql.sql index 21af327f13..172731b9c5 100644 --- a/dao/src/test/resources/sql/system-test-psql.sql +++ b/dao/src/test/resources/sql/system-test-psql.sql @@ -1,5 +1,2 @@ --PostgreSQL specific truncate to fit constraints -TRUNCATE TABLE device_credentials, device, device_profile, asset, asset_profile, ota_package, rule_node_state, rule_node, rule_chain, alarm_comment, alarm, entity_alarm; - --- Decrease seq_id column to make sure to cover cases of new sequential cycle during the tests -ALTER SEQUENCE edge_event_seq_id_seq MAXVALUE 256; +TRUNCATE TABLE device_credentials, device, device_profile, asset, asset_profile, ota_package, rule_node_state, rule_node, rule_chain, alarm_comment, alarm, entity_alarm; \ No newline at end of file From 3c6d70b2c4a114b757eaad1f2033fd7244948aac Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Fri, 15 Sep 2023 16:49:36 +0300 Subject: [PATCH 059/267] edge test speed up --- .../java/org/thingsboard/server/edge/AbstractEdgeTest.java | 3 ++- .../java/org/thingsboard/server/edge/TelemetryEdgeTest.java | 4 ---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 410348762f..689847416c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -102,7 +102,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. @TestPropertySource(properties = { "edges.enabled=true", - "queue.rule-engine.stats.enabled=false" + "queue.rule-engine.stats.enabled=false", + "edges.storage.sleep_between_batches=1000" }) abstract public class AbstractEdgeTest extends AbstractControllerTest { diff --git a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java index 922475f305..2ee267b88c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/TelemetryEdgeTest.java @@ -22,7 +22,6 @@ import com.google.protobuf.AbstractMessage; import org.awaitility.Awaitility; import org.junit.Assert; import org.junit.Test; -import org.springframework.test.context.TestPropertySource; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; @@ -42,9 +41,6 @@ import java.util.List; import java.util.concurrent.TimeUnit; @DaoSqlTest -@TestPropertySource(properties = { - "edges.storage.sleep_between_batches=1000" -}) public class TelemetryEdgeTest extends AbstractEdgeTest { @Test From 6f264dd698608fda821bfbb1dd5fa8b573c16c21 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 15 Sep 2023 17:42:04 +0300 Subject: [PATCH 060/267] Edge instructions css optimization --- .../edge-instructions-dialog.component.scss | 61 ++++++++----------- 1 file changed, 26 insertions(+), 35 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss index 092f3c6408..54dc438011 100644 --- a/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss +++ b/ui-ngx/src/app/modules/home/pages/edge/edge-instructions-dialog.component.scss @@ -14,11 +14,8 @@ * limitations under the License. */ -@use '@angular/material' as mat; @import "../../../../../scss/constants"; -@import '../theme.scss'; -$tb-primary: mat.get-color-from-palette($tb-primary); :host { height: 100%; max-height: 100vh; @@ -74,37 +71,34 @@ $tb-primary: mat.get-color-from-palette($tb-primary); :host ::ng-deep { .tb-markdown-view { padding: 16px 16px 32px 16px; - div.code-wrapper button.clipboard-btn { - right: -2px !important; - p { - color: $tb-primary !important; - } - p, div { - background-color: unset !important; - } - div { - img { - display: none; + div { + background-color: #F3F6FA; + &.code-wrapper button.clipboard-btn { + right: -2px !important; + p { + color: $tb-primary-color !important; } - &:after { - content: ""; - position: initial; - display: block; - width: 18px; - height: 18px; - background: $tb-primary; - mask-image: url(/assets/copy-code-icon.svg); - mask-repeat: no-repeat; + p, div { + background-color: unset !important; } - } - a { - color: $tb-primary; - &:hover { - color: $tb-primary; + div { + img { + display: none; + } + &:after { + content: ""; + position: initial; + display: block; + width: 18px; + height: 18px; + background: $tb-primary-color; + mask-image: url(/assets/copy-code-icon.svg); + mask-repeat: no-repeat; + } + } + &.multiline { + right: -2px !important; } - } - &.multiline { - right: -2px !important; } } & > *:not(ul) { @@ -112,10 +106,7 @@ $tb-primary: mat.get-color-from-palette($tb-primary); padding-left: unset !important; } pre[class*="language-"] { - border: 1px solid $tb-primary !important; - } - div { - background-color: #F3F6FA; + border: 1px solid $tb-primary-color !important; } } .mdc-button__label > span { From f08f3ea9219b0c70c543dff0bd2dfda1d15e4c07 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 18 Sep 2023 12:51:01 +0300 Subject: [PATCH 061/267] Replace the image URL to CDN --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 581e71977d..d479296869 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ ThingsBoard documentation is hosted on [thingsboard.io](https://thingsboard.io/d [![Smart farming](https://user-images.githubusercontent.com/8308069/152984443-a98b7d3d-ff7a-4037-9011-e71e1e6f755f.gif "Smart farming")](https://thingsboard.io/smart-farming/) [**IoT Rule Engine**](https://thingsboard.io/docs/user-guide/rule-engine-2-0/re-getting-started/) -[![IoT Rule Engine](https://thingsboard.io/images/demo/send-email-rule-chain.gif "IoT Rule Engine")](https://thingsboard.io/docs/user-guide/rule-engine-2-0/re-getting-started/) +[![IoT Rule Engine](https://img.thingsboard.io/demo/send-email-rule-chain.gif "IoT Rule Engine")](https://thingsboard.io/docs/user-guide/rule-engine-2-0/re-getting-started/) [**Smart metering**](https://thingsboard.io/smart-metering/) [![Smart metering](https://user-images.githubusercontent.com/8308069/31455788-6888a948-aec1-11e7-9819-410e0ba785e0.gif "Smart metering")](https://thingsboard.io/smart-metering/) From e4acb717f3459d54ef5f5e243ccba2bce2a53627 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 18 Sep 2023 14:52:50 +0300 Subject: [PATCH 062/267] Added SNMP_ENABLED=false for install edge instructions in case TB is already running on the same PC --- .../data/json/edge/install_instructions/centos/instructions.md | 1 + .../data/json/edge/install_instructions/ubuntu/instructions.md | 1 + 2 files changed, 2 insertions(+) diff --git a/application/src/main/data/json/edge/install_instructions/centos/instructions.md b/application/src/main/data/json/edge/install_instructions/centos/instructions.md index 0e9bf251c3..126c79b641 100644 --- a/application/src/main/data/json/edge/install_instructions/centos/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/centos/instructions.md @@ -199,6 +199,7 @@ export HTTP_BIND_PORT=18080 export MQTT_BIND_PORT=11883 export COAP_BIND_PORT=15683 export LWM2M_ENABLED=false +export SNMP_ENABLED=false EOL' {:copy-code} ``` diff --git a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md index 72b85e5190..425c08662b 100644 --- a/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md +++ b/application/src/main/data/json/edge/install_instructions/ubuntu/instructions.md @@ -131,6 +131,7 @@ export HTTP_BIND_PORT=18080 export MQTT_BIND_PORT=11883 export COAP_BIND_PORT=15683 export LWM2M_ENABLED=false +export SNMP_ENABLED=false EOL' {:copy-code} ``` From 241a1697f6739e13b767db7b53a8541b9a8d118d Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Mon, 18 Sep 2023 15:46:33 +0300 Subject: [PATCH 063/267] UI: Fixed toggle node library button for safari --- .../modules/home/pages/rulechain/rulechain-page.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 6911558ad4..0649c92ac9 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 @@ -159,7 +159,7 @@ - + \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],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","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=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}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.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}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.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}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt 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,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),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(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,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 \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{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 \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",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"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Lt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Mt=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"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,Pt;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(Dt||(Dt={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const wt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[Dt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[Dt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[Dt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[Dt.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),Ot=new Map([[Vt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[Vt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[Vt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[Vt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),Bt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Ut;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Ut||(Ut={}));const _t=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName: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,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.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([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:n,args:[{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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class jt 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,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt 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,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t 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,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt 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,[D.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt 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,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt 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,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.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:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Zt 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,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en 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,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,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 {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{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 {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn 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,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class rn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=_t,this.argumentTypeMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Bt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class on extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class an extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=_t,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Ut)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ln extends b{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.maxLength(255)]]})}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,qe(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}setDisabledState(e){e?this.messageTypeFormGroup.disable({emitEvent:!1}):this.messageTypeFormGroup.enable({emitEvent:!1})}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[D.required,D.maxLength(255)]:[D.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing",required:"required"},providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],ln.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}],required:[{type:i}]}});class sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[X(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]})}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1})),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e}),this.deduplicationConfigForm.get("queueName").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mn{}e("ExampleHintComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink"},ngImport:t,template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .custom-styles{display:flex;justify-content:space-between;gap:20px}:host .custom-styles .see-example{display:flex;flex-shrink:0}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .custom-styles{display:flex;justify-content:space-between;gap:20px}:host .custom-styles .see-example{display:flex;flex-shrink:0}\n"]}]}],propDecorators:{hintText:[{type:i}],popupHelpLink:[{type:i}]}});class un extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),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")}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));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:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],un.prototype,"disabled",void 0),Se([h()],un.prototype,"uniqueKeyValuePairValidator",void 0),Se([h()],un.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.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})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],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})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:C.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Fe(""),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))),ke())}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&&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 qe(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return qe(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},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))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:H.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>cn)),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:t,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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:a((()=>cn)),multi:!0}],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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.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){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),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([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.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 n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t){this.fb=e,this.translate=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.selectOptions=[];for(const e of wt.keys())this.selectOptions.push({value:e,name:this.translate.instant(wt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.FormBuilder},{type:H.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ae,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((()=>{this.updateModel()}))}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)X(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.at(e.length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],yn.prototype,"disabled",void 0),Se([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.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})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.separatorKeysCodes=[le,se,me]}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(D.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:H.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn extends b{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new Ae,this.alarmStatus=k,this.alarmStatusTranslations=L}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"],dependencies:[{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class vn{}e("RulenodeCoreConfigCommonModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[O,T,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:l,args:[{declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}]}]});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return Z(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,Z(e)}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}touched(){this.deviceAttributesConfigForm.get("attributesControl").markAsTouched()}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(ct))this.predefinedValues.push({value:ct[e],name:this.translate.instant(ft.get(ct[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=X(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=I,this.aggregations=Object.values(I),this.aggregationTypesTranslations=N,this.fetchMode=gt,this.samplingOrders=Object.values(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[D.required]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,Z(e)}prepareInputConfig(e){return ee(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:I.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),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("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=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}))}n&&(n.value="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===gt.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===I.NONE}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .tb-hint{padding-bottom:0}:host .description-block{display:flex;align-items:center;background:#F7F7F7;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{background:#FDF7F7;color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .tb-hint{padding-bottom:0}:host .description-block{display:flex;align-items:center;background:#F7F7F7;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{background:#FDF7F7;color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}touched(){this.originatorAttributesConfigForm.get("attributesControl").markAsTouched()}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return Z(e)}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n',dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=Ct,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Ae;for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===ht.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,Z(e)}prepareInputConfig(e){let t,n,r={[S.name.value]:`relatedEntity${this.translate.instant(S.name.name)}`},o={serialNumber:"sn"};return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,t===ht.FIELDS?r=n:o=n,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[]],svMap:[e.svMap,[]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===ht.FIELDS?(this.relatedAttributesConfigForm.get("svMap").setValidators(D.required),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("kvMap").clearValidators(),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("kvMap").setValidators(D.required),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("svMap").clearValidators(),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity())}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class An extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:l,args:[{declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}]}]});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.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"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.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("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Ne.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Mt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.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([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn 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,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&te(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){te(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=q,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ue.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn 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,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn 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,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.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,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],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,[D.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,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.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})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Bn 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,n=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([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.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})}}e("SendEmailConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn 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,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.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([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:He.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(A),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class _n 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,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Lt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}]}]});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:X(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[D.required]]})}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:hn,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:X(e?.messageNames)?e.messageNames:null,metadataNames:X(e?.metadataNames)?e.metadataNames:null,checkAllKeys:!!X(e?.checkAllKeys)&&e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(D.required,["messageNames","metadataNames"])})}touched(){this.checkMessageConfigForm.markAsTouched(),this.checkMessageConfigForm.updateValueAndValidity({emitEvent:!0})}}e("CheckMessageConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!X(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:X(e?.direction)?e.direction:null,entityType:X(e?.entityType)?e.entityType:null,entityId:X(e?.entityId)?e.entityId:null,relationType:X(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e.relationType,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.values(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.values(pt),this.rangeUnitTranslationMap=dt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:X(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:X(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:X(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!X(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:X(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:X(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:X(e?.centerLongitude)?e.centerLongitude:null,range:X(e?.range)?e.range:null,rangeUnit:X(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:X(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[D.required]],longitudeKeyName:[e.longitudeKeyName,[D.required]],perimeterType:[e.perimeterType,[D.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required]),this.defaultPaddingEnable=!1),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
{{ \'tb.rulenode.coordinate-field-hint\' | translate }}
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}:host .tb-hint{padding:0}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
{{ \'tb.rulenode.coordinate-field-hint\' | translate }}
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}:host .tb-hint{padding:0}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:X(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[D.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn 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}prepareInputConfig(e){return{originatorTypes:X(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[D.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:l,args:[{declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | 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 tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{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 tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class rr 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,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[D.required]],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]})}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr 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,[D.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}]}]});class dr{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","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","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.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required.","limit-range":"Limit should be in a range from 2 to 1000.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","timeseries-keys-required":"At least one timeseries key should be selected.","add-timeseries-key":"Add timeseries key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","add-metadata-field":"Add metadata field","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Value should be greater than 0 or unspecified.","relation-type":"Relation type","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","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-key":"Target key","target-key-required":"Target key is required.","attr-mapping-required":"At least one mapping entry should be specified.","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","originator-entity":"Entity","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","select-entity-types":"Select entity types","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","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 alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",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","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message 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","key-pattern":"Key pattern","key-pattern-hint":"Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","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":'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 node is 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. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"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-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","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":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required.","end-interval-required":"Interval end 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":'Press "Enter" to complete field input.',"select-details":"Select details","entity-details-id":"Id","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","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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":"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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","perimeter-key-name-required":"Perimeter key name is required.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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 timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15.","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-caching":"Use caching","use-caching-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-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","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting 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).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time-series","message-body-type":"Message","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","add-entity-type":"Add entity type","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use 0 to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","retained-message":"Retained","attributes-mapping":"Attributes mapping","latest-telemetry-mapping":"Latest telemetry mapping","add-mapped-attribute-to":"Add mapped attributes to","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to","add-mapped-fields-to":"Add mapped fields to","add-selected-details-to":"Add selected details to","clear-selected-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","fetch-credentials-to":"Fetch credentials to","add-originator-attributes-to":"Add originator attributes to","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"timeseries key",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end").',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and metadata patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch","mapping-of-customers-fields":"Mapping of customer's fields","map-fields-required":"All mapping fields are required.",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to","device-profiles":"Device profiles","mapping-of-tenant-fields":"Mapping of tenant's fields","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:H.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[O,T,Cn,er,Gn,zn,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:l,args:[{declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}]}],ctorParameters:function(){return[{type:H.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/select","@angular/material/core","@angular/material/slide-toggle","@shared/components/hint-tooltip-icon.component","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/material/icon","@angular/material/tooltip","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/chips","@shared/pipe/safe.pipe","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@angular/material/expansion","tslib","rxjs","@home/components/public-api","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/string-items-list.component","@shared/components/toggle-header.component","@shared/components/toggle-select.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,v,C,F,k,L,T,I,N,S,q,A,M,G,E,D,V,P,w,R,O,B,K,U,_,H,z,j,Q,$,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,ve,Ce,Fe,ke,Le,Te,Ie,Ne,Se,qe,Ae,Me,Ge,Ee,De,Ve,Pe,we,Re,Oe,Be,Ke,Ue,_e,He,ze,je,Qe,$e;return{setters:[function(e){t=e,n=e.Component,r=e.EventEmitter,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,v=e.MessageType,C=e.messageTypeNames,F=e,k=e.AlarmStatus,L=e.alarmStatusTranslations,T=e.SharedModule,I=e.AggregationType,N=e.aggregationTranslations,S=e.entityFields,q=e.NotificationType,A=e.SlackChanelType,M=e.SlackChanelTypesTranslateMap},function(e){G=e},function(e){E=e,D=e.Validators,V=e.NgControl,P=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS},function(e){R=e,O=e.CommonModule},function(e){B=e},function(e){K=e},function(e){U=e},function(e){_=e},function(e){H=e},function(e){z=e},function(e){j=e},function(e){Q=e},function(e){$=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.deepTrim,ee=e.isObject,te=e.isNotEmptyStr},function(e){ne=e},function(e){re=e},function(e){oe=e},function(e){ae=e},function(e){ie=e},function(e){le=e.ENTER,se=e.COMMA,me=e.SEMICOLON},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e.coerceBooleanProperty},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e.tap,ve=e.map,Ce=e.mergeMap,Fe=e.startWith,ke=e.share,Le=e.takeUntil},function(e){Te=e},function(e){Ie=e},function(e){Ne=e},function(e){Se=e.__decorate},function(e){qe=e.of,Ae=e.Subject},function(e){Me=e.HomeComponentsModule},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){Pe=e},function(e){we=e},function(e){Re=e},function(e){Oe=e},function(e){Be=e},function(e){Ke=e},function(e){Ue=e},function(e){_e=e},function(e){He=e},function(e){ze=e},function(e){je=e},function(e){Qe=e},function(e){$e=e}],execute:function(){class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ye 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,[D.required,D.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]],updateAttributesOnlyOnValueChange:[!!e&&e.updateAttributesOnlyOnValueChange,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1}),this.attributesConfigForm.get("updateAttributesOnlyOnValueChange").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{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 \n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xe 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,[D.required]]})}}e("CheckPointConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ze extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[D.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",o=this.clearAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.clearAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],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","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=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}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.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}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.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}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt 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,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),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(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,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 \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{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 \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",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"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Lt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Mt=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"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,Pt;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(Dt||(Dt={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const wt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[Dt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[Dt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[Dt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[Dt.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),Ot=new Map([[Vt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[Vt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[Vt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[Vt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),Bt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Ut;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Ut||(Ut={}));const _t=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName: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,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.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([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:n,args:[{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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class jt 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,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt 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,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t 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,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt 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,[D.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt 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,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt 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,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.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:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Zt 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,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en 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,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,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 {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{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 {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn 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,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class rn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=_t,this.argumentTypeMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Bt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class on extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class an extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=_t,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Ut)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ln extends b{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.maxLength(255)]]})}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,qe(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}setDisabledState(e){e?this.messageTypeFormGroup.disable({emitEvent:!1}):this.messageTypeFormGroup.enable({emitEvent:!1})}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[D.required,D.maxLength(255)]:[D.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing",required:"required"},providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],ln.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}],required:[{type:i}]}});class sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[X(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]})}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1})),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e}),this.deduplicationConfigForm.get("queueName").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mn{}e("ExampleHintComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink"},ngImport:t,template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"]}]}],propDecorators:{hintText:[{type:i}],popupHelpLink:[{type:i}]}});class un extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),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")}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));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:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],un.prototype,"disabled",void 0),Se([h()],un.prototype,"uniqueKeyValuePairValidator",void 0),Se([h()],un.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.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})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],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})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:C.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Fe(""),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))),ke())}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&&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 qe(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return qe(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},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))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:H.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>cn)),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:t,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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:a((()=>cn)),multi:!0}],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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.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){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),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([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.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 n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t){this.fb=e,this.translate=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.selectOptions=[];for(const e of wt.keys())this.selectOptions.push({value:e,name:this.translate.instant(wt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.FormBuilder},{type:H.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ae,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((()=>{this.updateModel()}))}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)X(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.at(e.length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],yn.prototype,"disabled",void 0),Se([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.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})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.separatorKeysCodes=[le,se,me],this.onTouched=()=>{}}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(D.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:H.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn extends b{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new Ae,this.alarmStatus=k,this.alarmStatusTranslations=L}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"],dependencies:[{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class vn{}e("RulenodeCoreConfigCommonModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[O,T,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:l,args:[{declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}]}]});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return Z(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,Z(e)}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(ct))this.predefinedValues.push({value:ct[e],name:this.translate.instant(ft.get(ct[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=X(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=I,this.aggregations=Object.values(I),this.aggregationTypesTranslations=N,this.fetchMode=gt,this.samplingOrders=Object.values(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[D.required]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,Z(e)}prepareInputConfig(e){return ee(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:I.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),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("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=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}))}n&&(n.value="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===gt.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===I.NONE}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return Z(e)}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n',dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=Ct,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Ae;for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===ht.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,Z(e)}prepareInputConfig(e){let t,n,r={[S.name.value]:`relatedEntity${this.translate.instant(S.name.name)}`},o={serialNumber:"sn"};return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,t===ht.FIELDS?r=n:o=n,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[]],svMap:[e.svMap,[]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===ht.FIELDS?(this.relatedAttributesConfigForm.get("svMap").setValidators(D.required),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("kvMap").clearValidators(),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("kvMap").setValidators(D.required),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("svMap").clearValidators(),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity())}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class An extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:l,args:[{declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}]}]});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.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"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.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("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Ne.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Mt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.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([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn 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,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&te(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){te(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=q,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ue.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn 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,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn 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,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.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,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],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,[D.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,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.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})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Bn 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,n=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([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.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})}}e("SendEmailConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn 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,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.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([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:He.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(A),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class _n 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,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Lt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}]}]});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:X(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[D.required]]})}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:hn,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:X(e?.messageNames)?e.messageNames:null,metadataNames:X(e?.metadataNames)?e.metadataNames:null,checkAllKeys:!!X(e?.checkAllKeys)&&e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(D.required,["messageNames","metadataNames"])})}get touchedValidationControl(){return["messageNames","metadataNames"].some((e=>this.checkMessageConfigForm.get(e).touched))}}e("CheckMessageConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!X(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:X(e?.direction)?e.direction:null,entityType:X(e?.entityType)?e.entityType:null,entityId:X(e?.entityId)?e.entityId:null,relationType:X(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e.relationType,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.values(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.values(pt),this.rangeUnitTranslationMap=dt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:X(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:X(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:X(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!X(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:X(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:X(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:X(e?.centerLongitude)?e.centerLongitude:null,range:X(e?.range)?e.range:null,rangeUnit:X(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:X(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[D.required]],longitudeKeyName:[e.longitudeKeyName,[D.required]],perimeterType:[e.perimeterType,[D.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required]),this.defaultPaddingEnable=!1),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:X(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[D.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn 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}prepareInputConfig(e){return{originatorTypes:X(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[D.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:l,args:[{declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | 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 tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{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 tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class rr 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,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[D.required]],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]})}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr 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,[D.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}]}]});class dr{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","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","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.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required.","limit-range":"Limit should be in a range from 2 to 1000.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","timeseries-keys-required":"At least one timeseries key should be selected.","add-timeseries-key":"Add timeseries key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","add-metadata-field":"Add metadata field","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Value should be greater than 0 or unspecified.","relation-type":"Relation type","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","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-key":"Target key","target-key-required":"Target key is required.","attr-mapping-required":"At least one mapping entry should be specified.","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","originator-entity":"Entity","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","select-entity-types":"Select entity types","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","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 alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",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","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message 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","key-pattern":"Key pattern","key-pattern-hint":"Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","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":'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 node is 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. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"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-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","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":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required.","end-interval-required":"Interval end 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":'Press "Enter" to complete field input.',"select-details":"Select details","entity-details-id":"Id","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","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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":"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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","perimeter-key-name-required":"Perimeter key name is required.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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 timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15.","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-caching":"Use caching","use-caching-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-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","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting 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).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time-series","message-body-type":"Message","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","add-entity-type":"Add entity type","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use 0 to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","retained-message":"Retained","attributes-mapping":"Attributes mapping","latest-telemetry-mapping":"Latest telemetry mapping","add-mapped-attribute-to":"Add mapped attributes to","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to","add-mapped-fields-to":"Add mapped fields to","add-selected-details-to":"Add selected details to","clear-selected-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","fetch-credentials-to":"Fetch credentials to","add-originator-attributes-to":"Add originator attributes to","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"timeseries key",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end").',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and metadata patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch","mapping-of-customers-fields":"Mapping of customer's fields","map-fields-required":"All mapping fields are required.",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to","device-profiles":"Device profiles","mapping-of-tenant-fields":"Mapping of tenant's fields","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:H.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[O,T,Cn,er,Gn,zn,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:l,args:[{declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}]}],ctorParameters:function(){return[{type:H.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From fb7b19243b9c447e7b2d44f31928e169f268a9b7 Mon Sep 17 00:00:00 2001 From: kalytka Date: Tue, 19 Sep 2023 12:47:15 +0300 Subject: [PATCH 071/267] Add type "button" for help popup --- ui-ngx/src/app/shared/components/help-popup.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/ui-ngx/src/app/shared/components/help-popup.component.html b/ui-ngx/src/app/shared/components/help-popup.component.html index 730d054b8b..6381ecdf73 100644 --- a/ui-ngx/src/app/shared/components/help-popup.component.html +++ b/ui-ngx/src/app/shared/components/help-popup.component.html @@ -34,6 +34,7 @@
\n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],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","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=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}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.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}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.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}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt 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,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),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(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,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 \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{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 \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",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"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Lt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Mt=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"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,Pt;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(Dt||(Dt={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const wt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[Dt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[Dt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[Dt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[Dt.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),Ot=new Map([[Vt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[Vt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[Vt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[Vt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),Bt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Ut;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Ut||(Ut={}));const _t=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName: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,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.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([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:n,args:[{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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class jt 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,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt 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,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t 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,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt 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,[D.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt 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,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt 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,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.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:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Zt 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,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en 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,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,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 {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{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 {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn 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,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class rn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=_t,this.argumentTypeMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Bt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class on extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class an extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=_t,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Ut)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ln extends b{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.maxLength(255)]]})}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,qe(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}setDisabledState(e){e?this.messageTypeFormGroup.disable({emitEvent:!1}):this.messageTypeFormGroup.enable({emitEvent:!1})}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[D.required,D.maxLength(255)]:[D.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing",required:"required"},providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],ln.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}],required:[{type:i}]}});class sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[X(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]})}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1})),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e}),this.deduplicationConfigForm.get("queueName").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mn{}e("ExampleHintComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink"},ngImport:t,template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"]}]}],propDecorators:{hintText:[{type:i}],popupHelpLink:[{type:i}]}});class un extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),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")}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));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:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],un.prototype,"disabled",void 0),Se([h()],un.prototype,"uniqueKeyValuePairValidator",void 0),Se([h()],un.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.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})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],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})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:C.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Fe(""),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))),ke())}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&&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 qe(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return qe(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},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))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:H.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>cn)),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:t,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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:a((()=>cn)),multi:!0}],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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.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){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),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([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.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 n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t){this.fb=e,this.translate=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.selectOptions=[];for(const e of wt.keys())this.selectOptions.push({value:e,name:this.translate.instant(wt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.FormBuilder},{type:H.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ae,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((()=>{this.updateModel()}))}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)X(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.at(e.length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],yn.prototype,"disabled",void 0),Se([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.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})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.separatorKeysCodes=[le,se,me],this.onTouched=()=>{}}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(D.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:H.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn extends b{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new Ae,this.alarmStatus=k,this.alarmStatusTranslations=L}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"],dependencies:[{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class vn{}e("RulenodeCoreConfigCommonModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[O,T,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:l,args:[{declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}]}]});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return Z(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,Z(e)}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(ct))this.predefinedValues.push({value:ct[e],name:this.translate.instant(ft.get(ct[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=X(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=I,this.aggregations=Object.values(I),this.aggregationTypesTranslations=N,this.fetchMode=gt,this.samplingOrders=Object.values(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[D.required]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,Z(e)}prepareInputConfig(e){return ee(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:I.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),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("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=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}))}n&&(n.value="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===gt.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===I.NONE}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return Z(e)}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n',dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=Ct,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Ae;for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===ht.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,Z(e)}prepareInputConfig(e){let t,n,r={[S.name.value]:`relatedEntity${this.translate.instant(S.name.name)}`},o={serialNumber:"sn"};return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,t===ht.FIELDS?r=n:o=n,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[]],svMap:[e.svMap,[]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===ht.FIELDS?(this.relatedAttributesConfigForm.get("svMap").setValidators(D.required),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("kvMap").clearValidators(),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("kvMap").setValidators(D.required),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("svMap").clearValidators(),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity())}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class An extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:l,args:[{declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}]}]});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.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"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.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("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Ne.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Mt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.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([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn 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,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&te(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){te(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=q,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ue.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn 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,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn 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,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.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,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],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,[D.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,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.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})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Bn 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,n=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([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.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})}}e("SendEmailConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn 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,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.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([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:He.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(A),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class _n 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,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Lt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}]}]});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:X(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[D.required]]})}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:hn,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:X(e?.messageNames)?e.messageNames:null,metadataNames:X(e?.metadataNames)?e.metadataNames:null,checkAllKeys:!!X(e?.checkAllKeys)&&e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(D.required,["messageNames","metadataNames"])})}get touchedValidationControl(){return["messageNames","metadataNames"].some((e=>this.checkMessageConfigForm.get(e).touched))}}e("CheckMessageConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!X(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:X(e?.direction)?e.direction:null,entityType:X(e?.entityType)?e.entityType:null,entityId:X(e?.entityId)?e.entityId:null,relationType:X(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e.relationType,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.values(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.values(pt),this.rangeUnitTranslationMap=dt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:X(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:X(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:X(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!X(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:X(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:X(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:X(e?.centerLongitude)?e.centerLongitude:null,range:X(e?.range)?e.range:null,rangeUnit:X(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:X(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[D.required]],longitudeKeyName:[e.longitudeKeyName,[D.required]],perimeterType:[e.perimeterType,[D.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required]),this.defaultPaddingEnable=!1),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:X(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[D.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn 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}prepareInputConfig(e){return{originatorTypes:X(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[D.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:l,args:[{declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | 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 tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{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 tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class rr 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,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[D.required]],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]})}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr 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,[D.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}]}]});class dr{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","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","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.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required.","limit-range":"Limit should be in a range from 2 to 1000.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","timeseries-keys-required":"At least one timeseries key should be selected.","add-timeseries-key":"Add timeseries key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","add-metadata-field":"Add metadata field","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Value should be greater than 0 or unspecified.","relation-type":"Relation type","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","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-key":"Target key","target-key-required":"Target key is required.","attr-mapping-required":"At least one mapping entry should be specified.","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","originator-entity":"Entity","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","select-entity-types":"Select entity types","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","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 alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",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","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message 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","key-pattern":"Key pattern","key-pattern-hint":"Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","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":'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 node is 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. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"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-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","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":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required.","end-interval-required":"Interval end 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":'Press "Enter" to complete field input.',"select-details":"Select details","entity-details-id":"Id","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","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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":"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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","perimeter-key-name-required":"Perimeter key name is required.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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 timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15.","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-caching":"Use caching","use-caching-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-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","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting 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).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time-series","message-body-type":"Message","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","add-entity-type":"Add entity type","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use 0 to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","retained-message":"Retained","attributes-mapping":"Attributes mapping","latest-telemetry-mapping":"Latest telemetry mapping","add-mapped-attribute-to":"Add mapped attributes to","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to","add-mapped-fields-to":"Add mapped fields to","add-selected-details-to":"Add selected details to","clear-selected-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","fetch-credentials-to":"Fetch credentials to","add-originator-attributes-to":"Add originator attributes to","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"timeseries key",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end").',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and metadata patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch","mapping-of-customers-fields":"Mapping of customer's fields","map-fields-required":"All mapping fields are required.",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to","device-profiles":"Device profiles","mapping-of-tenant-fields":"Mapping of tenant's fields","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:H.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[O,T,Cn,er,Gn,zn,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:l,args:[{declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}]}],ctorParameters:function(){return[{type:H.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map +System.register(["@angular/core","@shared/public-api","@ngrx/store","@angular/forms","@angular/common","@angular/material/checkbox","@angular/material/input","@angular/material/form-field","@angular/flex-layout/flex","@ngx-translate/core","@angular/material/select","@angular/material/core","@angular/material/slide-toggle","@shared/components/hint-tooltip-icon.component","@shared/components/queue/queue-autocomplete.component","@core/public-api","@shared/components/js-func.component","@angular/material/button","@angular/material/icon","@angular/material/tooltip","@shared/components/script-lang.component","@angular/cdk/keycodes","@angular/material/chips","@shared/pipe/safe.pipe","@shared/components/entity/entity-type-select.component","@shared/components/entity/entity-select.component","@angular/cdk/coercion","@shared/components/tb-error.component","@angular/flex-layout/extended","@angular/material/list","@angular/cdk/drag-drop","rxjs/operators","@angular/material/autocomplete","@shared/pipe/highlight.pipe","@angular/material/expansion","tslib","rxjs","@home/components/public-api","@shared/components/help-popup.component","@shared/components/entity/entity-subtype-list.component","@shared/components/relation/relation-type-autocomplete.component","@home/components/relation/relation-filters.component","@shared/components/file-input.component","@shared/components/button/toggle-password.component","@shared/components/string-items-list.component","@shared/components/toggle-header.component","@shared/components/toggle-select.component","@shared/components/entity/entity-list.component","@shared/components/notification/template-autocomplete.component","@shared/components/tb-checkbox.component","@home/components/sms/sms-provider-configuration.component","@angular/material/radio","@shared/components/slack-conversation-autocomplete.component","@shared/components/entity/entity-autocomplete.component","@shared/components/entity/entity-type-list.component"],(function(e){"use strict";var t,n,r,o,a,i,l,s,m,u,p,d,c,f,g,y,x,b,h,v,C,F,k,L,T,I,N,S,q,A,M,G,E,D,V,P,w,R,O,B,K,U,_,H,z,j,Q,$,J,Y,W,X,Z,ee,te,ne,re,oe,ae,ie,le,se,me,ue,pe,de,ce,fe,ge,ye,xe,be,he,ve,Ce,Fe,ke,Le,Te,Ie,Ne,Se,qe,Ae,Me,Ge,Ee,De,Ve,Pe,we,Re,Oe,Be,Ke,Ue,_e,He,ze,je,Qe,$e;return{setters:[function(e){t=e,n=e.Component,r=e.EventEmitter,o=e.ViewChild,a=e.forwardRef,i=e.Input,l=e.NgModule},function(e){s=e.RuleNodeConfigurationComponent,m=e.AttributeScope,u=e.telemetryTypeTranslations,p=e.ServiceType,d=e.ScriptLanguage,c=e.AlarmSeverity,f=e.alarmSeverityTranslations,g=e.EntitySearchDirection,y=e.entitySearchDirectionTranslations,x=e.EntityType,b=e.PageComponent,h=e.coerceBoolean,v=e.MessageType,C=e.messageTypeNames,F=e,k=e.AlarmStatus,L=e.alarmStatusTranslations,T=e.SharedModule,I=e.AggregationType,N=e.aggregationTranslations,S=e.entityFields,q=e.NotificationType,A=e.SlackChanelType,M=e.SlackChanelTypesTranslateMap},function(e){G=e},function(e){E=e,D=e.Validators,V=e.NgControl,P=e.NG_VALUE_ACCESSOR,w=e.NG_VALIDATORS},function(e){R=e,O=e.CommonModule},function(e){B=e},function(e){K=e},function(e){U=e},function(e){_=e},function(e){H=e},function(e){z=e},function(e){j=e},function(e){Q=e},function(e){$=e},function(e){J=e},function(e){Y=e.getCurrentAuthState,W=e,X=e.isDefinedAndNotNull,Z=e.deepTrim,ee=e.isObject,te=e.isNotEmptyStr},function(e){ne=e},function(e){re=e},function(e){oe=e},function(e){ae=e},function(e){ie=e},function(e){le=e.ENTER,se=e.COMMA,me=e.SEMICOLON},function(e){ue=e},function(e){pe=e},function(e){de=e},function(e){ce=e},function(e){fe=e.coerceBooleanProperty},function(e){ge=e},function(e){ye=e},function(e){xe=e},function(e){be=e},function(e){he=e.tap,ve=e.map,Ce=e.mergeMap,Fe=e.startWith,ke=e.share,Le=e.takeUntil},function(e){Te=e},function(e){Ie=e},function(e){Ne=e},function(e){Se=e.__decorate},function(e){qe=e.of,Ae=e.Subject},function(e){Me=e.HomeComponentsModule},function(e){Ge=e},function(e){Ee=e},function(e){De=e},function(e){Ve=e},function(e){Pe=e},function(e){we=e},function(e){Re=e},function(e){Oe=e},function(e){Be=e},function(e){Ke=e},function(e){Ue=e},function(e){_e=e},function(e){He=e},function(e){ze=e},function(e){je=e},function(e){Qe=e},function(e){$e=e}],execute:function(){class Je extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.emptyConfigForm}onConfigurationSet(e){this.emptyConfigForm=this.fb.group({})}}e("EmptyConfigComponent",Je),Je.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Je.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Je,selector:"tb-node-empty-config",usesInheritance:!0,ngImport:t,template:"
",isInline:!0}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Je,decorators:[{type:n,args:[{selector:"tb-node-empty-config",template:"
"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ye 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,[D.required,D.pattern(/.*\S.*/)]],createCustomerIfNotExists:[!!e&&e.createCustomerIfNotExists,[]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("AssignCustomerConfigComponent",Ye),Ye.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ye.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ye,selector:"tb-action-node-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ye,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class We extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u}configForm(){return this.attributesConfigForm}onConfigurationSet(e){this.attributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],notifyDevice:[!e||e.notifyDevice,[]],sendAttributesUpdatedNotification:[!!e&&e.sendAttributesUpdatedNotification,[]],updateAttributesOnlyOnValueChange:[!!e&&e.updateAttributesOnlyOnValueChange,[]]}),this.attributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.attributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1}),e===m.CLIENT_SCOPE&&this.attributesConfigForm.get("sendAttributesUpdatedNotification").patchValue(!1,{emitEvent:!1}),this.attributesConfigForm.get("updateAttributesOnlyOnValueChange").patchValue(!1,{emitEvent:!1})}))}}e("AttributesConfigComponent",We),We.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),We.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:We,selector:"tb-action-node-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:We,decorators:[{type:n,args:[{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 \n {{ \'tb.rulenode.update-attributes-only-on-value-change\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.send-attributes-updated-notification\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xe 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,[D.required]]})}}e("CheckPointConfigComponent",Xe),Xe.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xe.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xe,selector:"tb-action-node-check-point-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xe,decorators:[{type:n,args:[{selector:"tb-action-node-check-point-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Ze extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.clearAlarmConfigForm}onConfigurationSet(e){this.clearAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],alarmType:[e?e.alarmType:null,[D.required]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.clearAlarmConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.clearAlarmConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.clearAlarmConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(t===d.JS?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(t===d.TBEL?[D.required]:[]),this.clearAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.clearAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/clear_alarm_node_script_fn":"rulenode/tbel/clear_alarm_node_script_fn",o=this.clearAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.clearAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.clearAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ClearAlarmConfigComponent",Ze),Ze.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Ze.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ze,selector:"tb-action-node-clear-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ze,decorators:[{type:n,args:[{selector:"tb-action-node-clear-alarm-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class et extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.alarmSeverities=Object.keys(c),this.alarmSeverityTranslationMap=f,this.separatorKeysCodes=[le,se,me],this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-details-function"}configForm(){return this.createAlarmConfigForm}onConfigurationSet(e){this.createAlarmConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],alarmDetailsBuildJs:[e?e.alarmDetailsBuildJs:null,[]],alarmDetailsBuildTbel:[e?e.alarmDetailsBuildTbel:null,[]],useMessageAlarmData:[!!e&&e.useMessageAlarmData,[]],overwriteAlarmDetails:[!!e&&e.overwriteAlarmDetails,[]],alarmType:[e?e.alarmType:null,[]],severity:[e?e.severity:null,[]],propagate:[!!e&&e.propagate,[]],relationTypes:[e?e.relationTypes:null,[]],propagateToOwner:[!!e&&e.propagateToOwner,[]],propagateToTenant:[!!e&&e.propagateToTenant,[]],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","overwriteAlarmDetails","scriptLang"]}updateValidators(e){const t=this.createAlarmConfigForm.get("useMessageAlarmData").value,n=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;t?(this.createAlarmConfigForm.get("alarmType").setValidators([]),this.createAlarmConfigForm.get("severity").setValidators([])):(this.createAlarmConfigForm.get("alarmType").setValidators([D.required]),this.createAlarmConfigForm.get("severity").setValidators([D.required])),this.createAlarmConfigForm.get("alarmType").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("severity").updateValueAndValidity({emitEvent:e});let r=this.createAlarmConfigForm.get("scriptLang").value;r!==d.TBEL||this.tbelEnabled||(r=d.JS,this.createAlarmConfigForm.get("scriptLang").patchValue(r,{emitEvent:!1}),setTimeout((()=>{this.createAlarmConfigForm.updateValueAndValidity({emitEvent:!0})})));const o=!1===t||!0===n;this.createAlarmConfigForm.get("alarmDetailsBuildJs").setValidators(o&&r===d.JS?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").setValidators(o&&r===d.TBEL?[D.required]:[]),this.createAlarmConfigForm.get("alarmDetailsBuildJs").updateValueAndValidity({emitEvent:e}),this.createAlarmConfigForm.get("alarmDetailsBuildTbel").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.createAlarmConfigForm.get("scriptLang").value,n=t===d.JS?"alarmDetailsBuildJs":"alarmDetailsBuildTbel",r=t===d.JS?"rulenode/create_alarm_node_script_fn":"rulenode/tbel/create_alarm_node_script_fn",o=this.createAlarmConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"json",this.translate.instant("tb.rulenode.details"),"Details",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.createAlarmConfigForm.get(n).setValue(e),this.changeScript.emit())}))}removeKey(e,t){const n=this.createAlarmConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.createAlarmConfigForm.get(t).setValue(n,{emitEvent:!0}))}addKey(e,t){const n=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}))}n&&(n.value="")}onValidate(){const e=this.createAlarmConfigForm.get("useMessageAlarmData").value,t=this.createAlarmConfigForm.get("overwriteAlarmDetails").value;if(!e||t){this.createAlarmConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}}e("CreateAlarmConfigComponent",et),et.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),et.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:et,selector:"tb-action-node-create-alarm-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:et,decorators:[{type:n,args:[{selector:"tb-action-node-create-alarm-config",template:'
\n \n {{ \'tb.rulenode.use-message-alarm-data\' | translate }}\n \n \n {{ \'tb.rulenode.overwrite-alarm-details\' | translate }}\n \n
\n \n \n \n \n \n \n \n
\n \n
\n
\n
\n \n tb.rulenode.alarm-type\n \n \n {{ \'tb.rulenode.alarm-type-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-alarm-severity-pattern\' | translate }}\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-pattern\n \n \n {{ \'tb.rulenode.alarm-severity-required\' | translate }}\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 {{ \'tb.rulenode.propagate-to-owner\' | translate }}\n \n \n {{ \'tb.rulenode.propagate-to-tenant\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class tt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.createRelationConfigForm}onConfigurationSet(e){this.createRelationConfigForm=this.fb.group({direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[D.required]],entityNamePattern:[e?e.entityNamePattern:null,[]],entityTypePattern:[e?e.entityTypePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],createEntityIfNotExists:[!!e&&e.createEntityIfNotExists,[]],removeCurrentRelations:[!!e&&e.removeCurrentRelations,[]],changeOriginatorToRelatedEntity:[!!e&&e.changeOriginatorToRelatedEntity,[]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["entityType"]}updateValidators(e){const t=this.createRelationConfigForm.get("entityType").value;t?this.createRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)]):this.createRelationConfigForm.get("entityNamePattern").setValidators([]),!t||t!==x.DEVICE&&t!==x.ASSET?this.createRelationConfigForm.get("entityTypePattern").setValidators([]):this.createRelationConfigForm.get("entityTypePattern").setValidators([D.required,D.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}}e("CreateRelationConfigComponent",tt),tt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tt,selector:"tb-action-node-create-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.entity-type-pattern\n \n \n {{ \'tb.rulenode.entity-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nt extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.entityType=x}configForm(){return this.deleteRelationConfigForm}onConfigurationSet(e){this.deleteRelationConfigForm=this.fb.group({deleteForSingleEntity:[!!e&&e.deleteForSingleEntity,[]],direction:[e?e.direction:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationType:[e?e.relationType:null,[D.required]],entityCacheExpiration:[e?e.entityCacheExpiration:null,[D.required,D.min(0)]]})}validatorTriggers(){return["deleteForSingleEntity","entityType"]}updateValidators(e){const t=this.deleteRelationConfigForm.get("deleteForSingleEntity").value,n=this.deleteRelationConfigForm.get("entityType").value;t?this.deleteRelationConfigForm.get("entityType").setValidators([D.required]):this.deleteRelationConfigForm.get("entityType").setValidators([]),t&&n?this.deleteRelationConfigForm.get("entityNamePattern").setValidators([D.required,D.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}}e("DeleteRelationConfigComponent",nt),nt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nt,selector:"tb-action-node-delete-relation-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\n \n
\n \n tb.rulenode.relation-type-pattern\n \n \n {{ \'tb.rulenode.relation-type-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class rt 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,D.required],fetchAlarmRulesStateOnStart:[!!e&&e.fetchAlarmRulesStateOnStart,D.required]})}}e("DeviceProfileConfigComponent",rt),rt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rt,selector:"tb-device-profile-config",usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'tb.rulenode.persist-alarm-rules\' | translate }}\n \n \n {{ \'tb.rulenode.fetch-alarm-rules\' | translate }}\n \n
\n',dependencies:[{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ot extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-generator-function",this.serviceType=p.TB_RULE_ENGINE}configForm(){return this.generatorConfigForm}onConfigurationSet(e){this.generatorConfigForm=this.fb.group({msgCount:[e?e.msgCount:null,[D.required,D.min(0)]],periodInSeconds:[e?e.periodInSeconds:null,[D.required,D.min(1)]],originator:[e?e.originator:null,[]],scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]],queueName:[e?e.queueName:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.generatorConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.generatorConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.generatorConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.generatorConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.generatorConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.generatorConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.generatorConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS),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(e){const t=this.generatorConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/generator_node_script_fn":"rulenode/tbel/generator_node_script_fn",o=this.generatorConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"generate",this.translate.instant("tb.rulenode.generator"),"Generate",["prevMsg","prevMetadata","prevMsgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.generatorConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.generatorConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}var at;e("GeneratorConfigComponent",ot),ot.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),ot.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ot,selector:"tb-action-node-generator-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,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 \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ce.EntitySelectComponent,selector:"tb-entity-select",inputs:["allowedEntityTypes","useAliasEntityTypes","required","disabled"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ot,decorators:[{type:n,args:[{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 \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}}),function(e){e.CUSTOMER="CUSTOMER",e.TENANT="TENANT",e.RELATED="RELATED",e.ALARM_ORIGINATOR="ALARM_ORIGINATOR",e.ENTITY="ENTITY"}(at||(at={}));const it=new Map([[at.CUSTOMER,"tb.rulenode.originator-customer"],[at.TENANT,"tb.rulenode.originator-tenant"],[at.RELATED,"tb.rulenode.originator-related"],[at.ALARM_ORIGINATOR,"tb.rulenode.originator-alarm-originator"],[at.ENTITY,"tb.rulenode.originator-entity"]]);var lt;!function(e){e.CIRCLE="CIRCLE",e.POLYGON="POLYGON"}(lt||(lt={}));const st=new Map([[lt.CIRCLE,"tb.rulenode.perimeter-circle"],[lt.POLYGON,"tb.rulenode.perimeter-polygon"]]);var mt;!function(e){e.MILLISECONDS="MILLISECONDS",e.SECONDS="SECONDS",e.MINUTES="MINUTES",e.HOURS="HOURS",e.DAYS="DAYS"}(mt||(mt={}));const ut=new Map([[mt.MILLISECONDS,"tb.rulenode.time-unit-milliseconds"],[mt.SECONDS,"tb.rulenode.time-unit-seconds"],[mt.MINUTES,"tb.rulenode.time-unit-minutes"],[mt.HOURS,"tb.rulenode.time-unit-hours"],[mt.DAYS,"tb.rulenode.time-unit-days"]]);var pt;!function(e){e.METER="METER",e.KILOMETER="KILOMETER",e.FOOT="FOOT",e.MILE="MILE",e.NAUTICAL_MILE="NAUTICAL_MILE"}(pt||(pt={}));const dt=new Map([[pt.METER,"tb.rulenode.range-unit-meter"],[pt.KILOMETER,"tb.rulenode.range-unit-kilometer"],[pt.FOOT,"tb.rulenode.range-unit-foot"],[pt.MILE,"tb.rulenode.range-unit-mile"],[pt.NAUTICAL_MILE,"tb.rulenode.range-unit-nautical-mile"]]);var ct;!function(e){e.ID="ID",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"}(ct||(ct={}));const ft=new Map([[ct.ID,"tb.rulenode.entity-details-id"],[ct.TITLE,"tb.rulenode.entity-details-title"],[ct.COUNTRY,"tb.rulenode.entity-details-country"],[ct.STATE,"tb.rulenode.entity-details-state"],[ct.CITY,"tb.rulenode.entity-details-city"],[ct.ZIP,"tb.rulenode.entity-details-zip"],[ct.ADDRESS,"tb.rulenode.entity-details-address"],[ct.ADDRESS2,"tb.rulenode.entity-details-address2"],[ct.PHONE,"tb.rulenode.entity-details-phone"],[ct.EMAIL,"tb.rulenode.entity-details-email"],[ct.ADDITIONAL_INFO,"tb.rulenode.entity-details-additional_info"]]);var gt;!function(e){e.FIRST="FIRST",e.LAST="LAST",e.ALL="ALL"}(gt||(gt={}));const yt=new Map([[gt.FIRST,"tb.rulenode.first"],[gt.LAST,"tb.rulenode.last"],[gt.ALL,"tb.rulenode.all"]]),xt=new Map([[gt.FIRST,"tb.rulenode.first-mode-hint"],[gt.LAST,"tb.rulenode.last-mode-hint"],[gt.ALL,"tb.rulenode.all-mode-hint"]]);var bt,ht;!function(e){e.ASC="ASC",e.DESC="DESC"}(bt||(bt={})),function(e){e.ATTRIBUTES="ATTRIBUTES",e.LATEST_TELEMETRY="LATEST_TELEMETRY",e.FIELDS="FIELDS"}(ht||(ht={}));const vt=new Map([[ht.ATTRIBUTES,"tb.rulenode.attributes"],[ht.LATEST_TELEMETRY,"tb.rulenode.latest-telemetry"],[ht.FIELDS,"tb.rulenode.fields"]]),Ct=new Map([[ht.ATTRIBUTES,"tb.rulenode.add-mapped-attribute-to"],[ht.LATEST_TELEMETRY,"tb.rulenode.add-mapped-latest-telemetry-to"],[ht.FIELDS,"tb.rulenode.add-mapped-fields-to"]]),Ft=new Map([[bt.ASC,"tb.rulenode.ascending"],[bt.DESC,"tb.rulenode.descending"]]);var kt;!function(e){e.STANDARD="STANDARD",e.FIFO="FIFO"}(kt||(kt={}));const Lt=new Map([[kt.STANDARD,"tb.rulenode.sqs-queue-standard"],[kt.FIFO,"tb.rulenode.sqs-queue-fifo"]]),Tt=["anonymous","basic","cert.PEM"],It=new Map([["anonymous","tb.rulenode.credentials-anonymous"],["basic","tb.rulenode.credentials-basic"],["cert.PEM","tb.rulenode.credentials-pem"]]),Nt=["sas","cert.PEM"],St=new Map([["sas","tb.rulenode.credentials-sas"],["cert.PEM","tb.rulenode.credentials-pem"]]);var qt;!function(e){e.GET="GET",e.POST="POST",e.PUT="PUT",e.DELETE="DELETE"}(qt||(qt={}));const At=["US-ASCII","ISO-8859-1","UTF-8","UTF-16BE","UTF-16LE","UTF-16"],Mt=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"]]);var Gt;!function(e){e.CUSTOM="CUSTOM",e.ADD="ADD",e.SUB="SUB",e.MULT="MULT",e.DIV="DIV",e.SIN="SIN",e.SINH="SINH",e.COS="COS",e.COSH="COSH",e.TAN="TAN",e.TANH="TANH",e.ACOS="ACOS",e.ASIN="ASIN",e.ATAN="ATAN",e.ATAN2="ATAN2",e.EXP="EXP",e.EXPM1="EXPM1",e.SQRT="SQRT",e.CBRT="CBRT",e.GET_EXP="GET_EXP",e.HYPOT="HYPOT",e.LOG="LOG",e.LOG10="LOG10",e.LOG1P="LOG1P",e.CEIL="CEIL",e.FLOOR="FLOOR",e.FLOOR_DIV="FLOOR_DIV",e.FLOOR_MOD="FLOOR_MOD",e.ABS="ABS",e.MIN="MIN",e.MAX="MAX",e.POW="POW",e.SIGNUM="SIGNUM",e.RAD="RAD",e.DEG="DEG"}(Gt||(Gt={}));const Et=new Map([[Gt.CUSTOM,{value:Gt.CUSTOM,name:"Custom Function",description:"Use this function to specify complex mathematical expression.",minArgs:1,maxArgs:16}],[Gt.ADD,{value:Gt.ADD,name:"Addition",description:"x + y",minArgs:2,maxArgs:2}],[Gt.SUB,{value:Gt.SUB,name:"Subtraction",description:"x - y",minArgs:2,maxArgs:2}],[Gt.MULT,{value:Gt.MULT,name:"Multiplication",description:"x * y",minArgs:2,maxArgs:2}],[Gt.DIV,{value:Gt.DIV,name:"Division",description:"x / y",minArgs:2,maxArgs:2}],[Gt.SIN,{value:Gt.SIN,name:"Sine",description:"Returns the trigonometric sine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.SINH,{value:Gt.SINH,name:"Hyperbolic sine",description:"Returns the hyperbolic sine of an argument.",minArgs:1,maxArgs:1}],[Gt.COS,{value:Gt.COS,name:"Cosine",description:"Returns the trigonometric cosine of an angle in radians.",minArgs:1,maxArgs:1}],[Gt.COSH,{value:Gt.COSH,name:"Hyperbolic cosine",description:"Returns the hyperbolic cosine of an argument.",minArgs:1,maxArgs:1}],[Gt.TAN,{value:Gt.TAN,name:"Tangent",description:"Returns the trigonometric tangent of an angle in radians",minArgs:1,maxArgs:1}],[Gt.TANH,{value:Gt.TANH,name:"Hyperbolic tangent",description:"Returns the hyperbolic tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ACOS,{value:Gt.ACOS,name:"Arc cosine",description:"Returns the arc cosine of an argument",minArgs:1,maxArgs:1}],[Gt.ASIN,{value:Gt.ASIN,name:"Arc sine",description:"Returns the arc sine of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN,{value:Gt.ATAN,name:"Arc tangent",description:"Returns the arc tangent of an argument",minArgs:1,maxArgs:1}],[Gt.ATAN2,{value:Gt.ATAN2,name:"2-argument arc tangent",description:"Returns the angle theta from the conversion of rectangular coordinates (x, y) to polar coordinates (r, theta)",minArgs:2,maxArgs:2}],[Gt.EXP,{value:Gt.EXP,name:"Exponential",description:"Returns Euler's number e raised to the power of an argument",minArgs:1,maxArgs:1}],[Gt.EXPM1,{value:Gt.EXPM1,name:"Exponential minus one",description:"Returns Euler's number e raised to the power of an argument minus one",minArgs:1,maxArgs:1}],[Gt.SQRT,{value:Gt.SQRT,name:"Square",description:"Returns the correctly rounded positive square root of an argument",minArgs:1,maxArgs:1}],[Gt.CBRT,{value:Gt.CBRT,name:"Cube root",description:"Returns the cube root of an argument",minArgs:1,maxArgs:1}],[Gt.GET_EXP,{value:Gt.GET_EXP,name:"Get exponent",description:"Returns the unbiased exponent used in the representation of an argument",minArgs:1,maxArgs:1}],[Gt.HYPOT,{value:Gt.HYPOT,name:"Square root",description:"Returns the square root of the squares of the arguments",minArgs:2,maxArgs:2}],[Gt.LOG,{value:Gt.LOG,name:"Logarithm",description:"Returns the natural logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG10,{value:Gt.LOG10,name:"Base 10 logarithm",description:"Returns the base 10 logarithm of an argument",minArgs:1,maxArgs:1}],[Gt.LOG1P,{value:Gt.LOG1P,name:"Logarithm of the sum",description:"Returns the natural logarithm of the sum of an argument",minArgs:1,maxArgs:1}],[Gt.CEIL,{value:Gt.CEIL,name:"Ceiling",description:"Returns the smallest (closest to negative infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR,{value:Gt.FLOOR,name:"Floor",description:"Returns the largest (closest to positive infinity) of an argument",minArgs:1,maxArgs:1}],[Gt.FLOOR_DIV,{value:Gt.FLOOR_DIV,name:"Floor division",description:"Returns the largest (closest to positive infinity) of the arguments",minArgs:2,maxArgs:2}],[Gt.FLOOR_MOD,{value:Gt.FLOOR_MOD,name:"Floor modulus",description:"Returns the floor modulus of the arguments",minArgs:2,maxArgs:2}],[Gt.ABS,{value:Gt.ABS,name:"Absolute",description:"Returns the absolute value of an argument",minArgs:1,maxArgs:1}],[Gt.MIN,{value:Gt.MIN,name:"Min",description:"Returns the smaller of the arguments",minArgs:2,maxArgs:2}],[Gt.MAX,{value:Gt.MAX,name:"Max",description:"Returns the greater of the arguments",minArgs:2,maxArgs:2}],[Gt.POW,{value:Gt.POW,name:"Raise to a power",description:"Returns the value of the first argument raised to the power of the second argument",minArgs:2,maxArgs:2}],[Gt.SIGNUM,{value:Gt.SIGNUM,name:"Sign of a real number",description:"Returns the signum function of the argument",minArgs:1,maxArgs:1}],[Gt.RAD,{value:Gt.RAD,name:"Radian",description:"Converts an angle measured in degrees to an approximately equivalent angle measured in radians",minArgs:1,maxArgs:1}],[Gt.DEG,{value:Gt.DEG,name:"Degrees",description:"Converts an angle measured in radians to an approximately equivalent angle measured in degrees.",minArgs:1,maxArgs:1}]]);var Dt,Vt,Pt;!function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES",e.CONSTANT="CONSTANT"}(Dt||(Dt={})),function(e){e.MESSAGE_BODY="MESSAGE_BODY",e.MESSAGE_METADATA="MESSAGE_METADATA",e.ATTRIBUTE="ATTRIBUTE",e.TIME_SERIES="TIME_SERIES"}(Vt||(Vt={})),function(e){e.DATA="DATA",e.METADATA="METADATA"}(Pt||(Pt={}));const wt=new Map([[Pt.DATA,"tb.rulenode.message"],[Pt.METADATA,"tb.rulenode.metadata"]]),Rt=new Map([[Dt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Fetch argument value from incoming message"}],[Dt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Fetch argument value from incoming message metadata"}],[Dt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Fetch attribute value from database"}],[Dt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Fetch latest time-series value from database"}],[Dt.CONSTANT,{name:"tb.rulenode.constant-type",description:"Define constant value"}]]),Ot=new Map([[Vt.MESSAGE_BODY,{name:"tb.rulenode.message-body-type",description:"Add result to the outgoing message"}],[Vt.MESSAGE_METADATA,{name:"tb.rulenode.message-metadata-type",description:"Add result to the outgoing message metadata"}],[Vt.ATTRIBUTE,{name:"tb.rulenode.attribute-type",description:"Store result as an entity attribute in the database"}],[Vt.TIME_SERIES,{name:"tb.rulenode.time-series-type",description:"Store result as an entity time-series in the database"}]]),Bt=["x","y","z","a","b","c","d","k","l","m","n","o","p","r","s","t"];var Kt,Ut;!function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE",e.CLIENT_SCOPE="CLIENT_SCOPE"}(Kt||(Kt={})),function(e){e.SHARED_SCOPE="SHARED_SCOPE",e.SERVER_SCOPE="SERVER_SCOPE"}(Ut||(Ut={}));const _t=new Map([[Kt.SHARED_SCOPE,"tb.rulenode.shared-scope"],[Kt.SERVER_SCOPE,"tb.rulenode.server-scope"],[Kt.CLIENT_SCOPE,"tb.rulenode.client-scope"]]);class Ht extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.keys(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.keys(pt),this.rangeUnitTranslationMap=dt,this.timeUnits=Object.keys(mt),this.timeUnitsTranslationMap=ut}configForm(){return this.geoActionConfigForm}onConfigurationSet(e){this.geoActionConfigForm=this.fb.group({latitudeKeyName:[e?e.latitudeKeyName:null,[D.required]],longitudeKeyName:[e?e.longitudeKeyName:null,[D.required]],perimeterType:[e?e.perimeterType:null,[D.required]],fetchPerimeterInfoFromMessageMetadata:[!!e&&e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e?e.perimeterKeyName: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,[D.required,D.min(1),D.max(2147483647)]],minInsideDurationTimeUnit:[e?e.minInsideDurationTimeUnit:null,[D.required]],minOutsideDuration:[e?e.minOutsideDuration:null,[D.required,D.min(1),D.max(2147483647)]],minOutsideDurationTimeUnit:[e?e.minOutsideDurationTimeUnit:null,[D.required]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoActionConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoActionConfigForm.get("perimeterType").value;t?this.geoActionConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoActionConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.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([D.required,D.min(-90),D.max(90)]),this.geoActionConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoActionConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoActionConfigForm.get("rangeUnit").setValidators([D.required])),t||n!==lt.POLYGON?this.geoActionConfigForm.get("polygonsDefinition").setValidators([]):this.geoActionConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoActionConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoActionConfigComponent",Ht),Ht.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ht.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ht,selector:"tb-action-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ht,decorators:[{type:n,args:[{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.perimeter-type\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n \n tb.rulenode.perimeter-key-name\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zt extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-to-string-function"}configForm(){return this.logConfigForm}onConfigurationSet(e){this.logConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.logConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.logConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.logConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.logConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.logConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.logConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.logConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.logConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/log_node_script_fn":"rulenode/tbel/log_node_script_fn",o=this.logConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"string",this.translate.instant("tb.rulenode.to-string"),"ToString",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.logConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.logConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("LogConfigComponent",zt),zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:zt,selector:"tb-action-node-log-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zt,decorators:[{type:n,args:[{selector:"tb-action-node-log-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class jt 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,[D.required,D.min(1)]],telemetryPrefix:[e?e.telemetryPrefix:null,[D.required]]})}}e("MsgCountConfigComponent",jt),jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jt,selector:"tb-action-node-msg-count-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Qt 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,[D.required,D.min(1),D.max(1e5)]]})}validatorTriggers(){return["useMetadataPeriodInSecondsPatterns"]}updateValidators(e){this.msgDelayConfigForm.get("useMetadataPeriodInSecondsPatterns").value?(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([D.required]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([])):(this.msgDelayConfigForm.get("periodInSecondsPattern").setValidators([]),this.msgDelayConfigForm.get("periodInSeconds").setValidators([D.required,D.min(0)])),this.msgDelayConfigForm.get("periodInSecondsPattern").updateValueAndValidity({emitEvent:e}),this.msgDelayConfigForm.get("periodInSeconds").updateValueAndValidity({emitEvent:e})}}e("MsgDelayConfigComponent",Qt),Qt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qt,selector:"tb-action-node-msg-delay-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qt,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class $t 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,[D.required]]})}}e("PushToCloudConfigComponent",$t),$t.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$t.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$t,selector:"tb-action-node-push-to-cloud-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$t,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jt 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,[D.required]]})}}e("PushToEdgeConfigComponent",Jt),Jt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jt,selector:"tb-action-node-push-to-edge-config",usesInheritance:!0,ngImport:t,template:'
\n \n attribute.attributes-scope\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Yt 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,[]]})}}e("RpcReplyConfigComponent",Yt),Yt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yt,selector:"tb-action-node-rpc-reply-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n',dependencies:[{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yt,decorators:[{type:n,args:[{selector:"tb-action-node-rpc-reply-config",template:'
\n \n tb.rulenode.request-id-metadata-attribute\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wt 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,[D.required,D.min(0)]]})}}e("RpcRequestConfigComponent",Wt),Wt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wt,selector:"tb-action-node-rpc-request-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xt extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null}ngOnInit(){this.ngControl=this.injector.get(V),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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.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:["",[D.required]],value:["",[D.required]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigOldComponent",Xt),Xt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Xt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xt,selector:"tb-kv-map-config-old",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",required:"required"},providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ge.TbErrorComponent,selector:"tb-error",inputs:["noMargin","error"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xt,decorators:[{type:n,args:[{selector:"tb-kv-map-config-old",providers:[{provide:P,useExisting:a((()=>Xt)),multi:!0},{provide:w,useExisting:a((()=>Xt)),multi:!0}],template:'
\n
\n {{ keyText | translate }}\n {{ valText | translate }}\n \n
\n
\n
\n \n \n \n {{ keyRequiredText | translate }}\n \n \n \n \n \n {{ valRequiredText | translate }}\n \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:#757575;font-size:12px;font-weight:700;white-space:nowrap}:host .tb-kv-map-config .body{padding-left:5px;padding-right:5px;padding-bottom:0;max-height:300px;overflow:auto}:host .tb-kv-map-config .body .cell{padding-left:5px;padding-right:5px}:host .tb-kv-map-config tb-error{display:block;margin-top:-12px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],required:[{type:i}]}});class Zt 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,[D.required,D.pattern(/.*\S.*/)]],fieldsMapping:[e?e.fieldsMapping:null,[D.required]]})}prepareOutputConfig(e){return e.tableName=e.tableName.trim(),e}}e("SaveToCustomTableConfigComponent",Zt),Zt.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Zt.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zt,selector:"tb-action-node-custom-table-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zt,decorators:[{type:n,args:[{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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class en 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,[D.required,D.min(0)]],skipLatestPersistence:[!!e&&e.skipLatestPersistence,[]],useServerTs:[!!e&&e.useServerTs,[]]})}}e("TimeseriesConfigComponent",en),en.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),en.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:en,selector:"tb-action-node-timeseries-config",usesInheritance:!0,ngImport:t,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 {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:en,decorators:[{type:n,args:[{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 {{ \'tb.rulenode.skip-latest-persistence\' | translate }}\n \n \n {{ \'tb.rulenode.use-server-ts\' | translate }}\n \n
tb.rulenode.use-server-ts-hint
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class tn 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,[D.required,D.pattern(/.*\S.*/)]],customerCacheExpiration:[e?e.customerCacheExpiration:null,[D.required,D.min(0)]]})}prepareOutputConfig(e){return e.customerNamePattern=e.customerNamePattern.trim(),e}}e("UnassignCustomerConfigComponent",tn),tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tn,selector:"tb-action-node-un-assign-to-customer-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.customer-name-pattern\n \n \n {{ \'tb.rulenode.customer-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tn,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.attributeScopeMap=m,this.attributeScopes=Object.keys(m),this.telemetryTypeTranslationsMap=u,this.separatorKeysCodes=[le,se,me]}configForm(){return this.deleteAttributesConfigForm}onConfigurationSet(e){this.deleteAttributesConfigForm=this.fb.group({scope:[e?e.scope:null,[D.required]],keys:[e?e.keys:null,[D.required]],sendAttributesDeletedNotification:[!!e&&e.sendAttributesDeletedNotification,[]],notifyDevice:[!!e&&e.notifyDevice,[]]}),this.deleteAttributesConfigForm.get("scope").valueChanges.subscribe((e=>{e!==m.SHARED_SCOPE&&this.deleteAttributesConfigForm.get("notifyDevice").patchValue(!1,{emitEvent:!1})}))}removeKey(e){const t=this.deleteAttributesConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteAttributesConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteAttributesConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteAttributesConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteAttributesConfigComponent",nn),nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nn,selector:"tb-action-node-delete-attributes-config",viewQueries:[{propertyName:"attributeChipList",first:!0,predicate:["attributeChipList"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nn,decorators:[{type:n,args:[{selector:"tb-action-node-delete-attributes-config",template:'
\n \n {{ \'attribute.attributes-scope\' | translate }}\n \n \n {{ telemetryTypeTranslationsMap.get(scope) | translate }}\n \n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.attributes-keys-required\' | translate }}\n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.send-attributes-deleted-notification\' | translate }}\n \n
tb.rulenode.send-attributes-deleted-notification-hint
\n
\n \n {{ \'tb.rulenode.notify-device\' | translate }}\n \n
tb.rulenode.notify-device-delete-hint
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]},propDecorators:{attributeChipList:[{type:o,args:["attributeChipList"]}]}});class rn extends b{get function(){return this.functionValue}set function(e){e&&this.functionValue!==e&&(this.functionValue=e,this.setupArgumentsFormGroup(!0))}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.maxArgs=16,this.minArgs=1,this.displayArgumentName=!1,this.mathFunctionMap=Et,this.ArgumentType=Dt,this.attributeScopeMap=_t,this.argumentTypeMap=Rt,this.arguments=Object.values(Dt),this.attributeScope=Object.values(Kt),this.propagateChange=null,this.valueChangeSubscription=[]}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.argumentsFormGroup=this.fb.group({arguments:this.fb.array([])}),this.valueChangeSubscription.push(this.argumentsFormGroup.valueChanges.subscribe((()=>{this.updateModel()}))),this.setupArgumentsFormGroup()}onDrop(e){const t=this.argumentsFormArray(),n=t.at(e.previousIndex);t.removeAt(e.previousIndex),t.insert(e.currentIndex,n),this.updateArgumentNames()}argumentsFormArray(){return this.argumentsFormGroup.get("arguments")}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.argumentsFormGroup.disable({emitEvent:!1}):(this.argumentsFormGroup.enable({emitEvent:!1}),this.argumentsFormGroup.get("arguments").controls.forEach((e=>this.updateArgumentControlValidators(e))))}ngOnDestroy(){this.valueChangeSubscription.length&&this.valueChangeSubscription.forEach((e=>e.unsubscribe()))}writeValue(e){const t=[];e&&e.forEach(((e,n)=>{t.push(this.createArgumentControl(e,n))})),this.argumentsFormGroup.setControl("arguments",this.fb.array(t),{emitEvent:!1}),this.setupArgumentsFormGroup()}removeArgument(e){this.argumentsFormGroup.get("arguments").removeAt(e),this.updateArgumentNames()}addArgument(e=!0){const t=this.argumentsFormGroup.get("arguments"),n=this.createArgumentControl(null,t.length);t.push(n,{emitEvent:e})}validate(e){return this.argumentsFormGroup.valid?null:{argumentsRequired:!0}}setupArgumentsFormGroup(e=!1){if(this.function&&(this.maxArgs=this.mathFunctionMap.get(this.function).maxArgs,this.minArgs=this.mathFunctionMap.get(this.function).minArgs,this.displayArgumentName=this.function===Gt.CUSTOM),this.argumentsFormGroup){for(this.argumentsFormGroup.get("arguments").setValidators([D.minLength(this.minArgs),D.maxLength(this.maxArgs)]),this.argumentsFormGroup.get("arguments").value.length>this.maxArgs&&(this.argumentsFormGroup.get("arguments").controls.length=this.maxArgs);this.argumentsFormGroup.get("arguments").value.length{this.updateArgumentControlValidators(n),n.get("attributeScope").updateValueAndValidity({emitEvent:!1}),n.get("defaultValue").updateValueAndValidity({emitEvent:!1})}))),n}updateArgumentControlValidators(e){const t=e.get("type").value;t===Dt.ATTRIBUTE?e.get("attributeScope").enable({emitEvent:!1}):e.get("attributeScope").disable({emitEvent:!1}),t&&t!==Dt.CONSTANT?e.get("defaultValue").enable({emitEvent:!1}):e.get("defaultValue").disable({emitEvent:!1})}updateArgumentNames(){this.argumentsFormGroup.get("arguments").controls.forEach(((e,t)=>{e.get("name").setValue(Bt[t])}))}updateModel(){const e=this.argumentsFormGroup.get("arguments").value;e.length&&this.argumentsFormGroup.valid?this.propagateChange(e):this.propagateChange(null)}}e("ArgumentsMapConfigComponent",rn),rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rn,selector:"tb-arguments-map-config",inputs:{disabled:"disabled",function:"function"},providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:xe.MatList,selector:"mat-list",exportAs:["matList"]},{kind:"component",type:xe.MatListItem,selector:"mat-list-item, a[mat-list-item], button[mat-list-item]",inputs:["activated"],exportAs:["matListItem"]},{kind:"directive",type:be.CdkDropList,selector:"[cdkDropList], cdk-drop-list",inputs:["cdkDropListConnectedTo","cdkDropListData","cdkDropListOrientation","id","cdkDropListLockAxis","cdkDropListDisabled","cdkDropListSortingDisabled","cdkDropListEnterPredicate","cdkDropListSortPredicate","cdkDropListAutoScrollDisabled","cdkDropListAutoScrollStep"],outputs:["cdkDropListDropped","cdkDropListEntered","cdkDropListExited","cdkDropListSorted"],exportAs:["cdkDropList"]},{kind:"directive",type:be.CdkDrag,selector:"[cdkDrag]",inputs:["cdkDragData","cdkDragLockAxis","cdkDragRootElement","cdkDragBoundary","cdkDragStartDelay","cdkDragFreeDragPosition","cdkDragDisabled","cdkDragConstrainPosition","cdkDragPreviewClass","cdkDragPreviewContainer"],outputs:["cdkDragStarted","cdkDragReleased","cdkDragEnded","cdkDragEntered","cdkDragExited","cdkDragDropped","cdkDragMoved"],exportAs:["cdkDrag"]},{kind:"directive",type:be.CdkDragHandle,selector:"[cdkDragHandle]",inputs:["cdkDragHandleDisabled"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormArrayName,selector:"[formArrayName]",inputs:["formArrayName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rn,decorators:[{type:n,args:[{selector:"tb-arguments-map-config",providers:[{provide:P,useExisting:a((()=>rn)),multi:!0},{provide:w,useExisting:a((()=>rn)),multi:!0}],template:'
\n\n
\n \n \n
\n \n
\n {{argumentControl.get(\'name\').value}}.\n
\n \n tb.rulenode.argument-source-field-input\n \n \n {{ argumentTypeMap.get(argumentControl.get(\'type\').value)?.name | translate }}\n \n \n {{ argumentTypeMap.get(argument).name | translate }}\n \n {{ argumentTypeMap.get(argument).description }}\n \n \n \n \n tb.rulenode.argument-source-field-input-required\n \n \n
\n \n tb.rulenode.argument-key-field-input\n \n \n help\n \n \n tb.rulenode.argument-key-field-input-required\n \n \n \n tb.rulenode.constant-value-field-input\n \n \n tb.rulenode.constant-value-field-input-required\n \n \n \n tb.rulenode.default-value-field-input\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n tb.rulenode.attribute-scope-field-input-required\n \n \n
\n \n
\n
\n
\n
\n
\n
\n tb.rulenode.no-arguments-prompt\n
\n \n
\n',styles:[":host .mat-mdc-list-item.tb-argument{border:solid rgba(0,0,0,.25) 1px;border-radius:4px;padding:10px 0;margin-bottom:16px}:host .arguments-list{padding:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],function:[{type:i}]}});class on extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.searchText="",this.dirty=!1,this.mathOperation=[...Et.values()],this.propagateChange=null}ngOnInit(){this.mathFunctionForm=this.fb.group({operation:[""]}),this.filteredOptions=this.mathFunctionForm.get("operation").valueChanges.pipe(he((e=>{let t;t="string"==typeof e&&Gt[e]?Gt[e]:null,this.updateView(t)})),ve((e=>(this.searchText=e||"",e?this._filter(e):this.mathOperation.slice()))))}_filter(e){const t=e.toLowerCase();return this.mathOperation.filter((e=>e.name.toLowerCase().includes(t)||e.value.toLowerCase().includes(t)))}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.mathFunctionForm.disable({emitEvent:!1}):this.mathFunctionForm.enable({emitEvent:!1})}mathFunctionDisplayFn(e){if(e){const t=Et.get(e);return t.value+" | "+t.name}return""}writeValue(e){this.modelValue=e,this.mathFunctionForm.get("operation").setValue(e,{emitEvent:!1}),this.dirty=!0}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}onFocus(){this.dirty&&(this.mathFunctionForm.get("operation").updateValueAndValidity({onlySelf:!0}),this.dirty=!1)}clear(){this.mathFunctionForm.get("operation").patchValue(""),setTimeout((()=>{this.operationInput.nativeElement.blur(),this.operationInput.nativeElement.focus()}),0)}}e("MathFunctionAutocompleteComponent",on),on.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),on.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:on,selector:"tb-math-function-autocomplete",inputs:{required:"required",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],viewQueries:[{propertyName:"operationInput",first:!0,predicate:["operationInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:on,decorators:[{type:n,args:[{selector:"tb-math-function-autocomplete",providers:[{provide:P,useExisting:a((()=>on)),multi:!0}],template:'\n tb.rulenode.functions-field-input\n \n \n \n \n \n \n {{ option.description }}\n \n \n \n tb.rulenode.no-option-found\n \n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.UntypedFormBuilder}]},propDecorators:{required:[{type:i}],disabled:[{type:i}],operationInput:[{type:o,args:["operationInput",{static:!0}]}]}});class an extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.MathFunction=Gt,this.ArgumentTypeResult=Vt,this.argumentTypeResultMap=Ot,this.attributeScopeMap=_t,this.argumentsResult=Object.values(Vt),this.attributeScopeResult=Object.values(Ut)}configForm(){return this.mathFunctionConfigForm}onConfigurationSet(e){this.mathFunctionConfigForm=this.fb.group({operation:[e?e.operation:null,[D.required]],arguments:[e?e.arguments:null,[D.required]],customFunction:[e?e.customFunction:"",[D.required]],result:this.fb.group({type:[e?e.result.type:null,[D.required]],attributeScope:[e?e.result.attributeScope:null,[D.required]],key:[e?e.result.key:"",[D.required]],resultValuePrecision:[e?e.result.resultValuePrecision:0],addToBody:[!!e&&e.result.addToBody],addToMetadata:[!!e&&e.result.addToMetadata]})})}updateValidators(e){const t=this.mathFunctionConfigForm.get("operation").value,n=this.mathFunctionConfigForm.get("result.type").value;t===Gt.CUSTOM?this.mathFunctionConfigForm.get("customFunction").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("customFunction").disable({emitEvent:!1}),n===Vt.ATTRIBUTE?this.mathFunctionConfigForm.get("result.attributeScope").enable({emitEvent:!1}):this.mathFunctionConfigForm.get("result.attributeScope").disable({emitEvent:!1}),this.mathFunctionConfigForm.get("customFunction").updateValueAndValidity({emitEvent:e}),this.mathFunctionConfigForm.get("result.attributeScope").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["operation","result.type"]}}e("MathFunctionConfigComponent",an),an.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),an.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:an,selector:"tb-action-node-math-function-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"directive",type:z.MatSelectTrigger,selector:"mat-select-trigger"},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:rn,selector:"tb-arguments-map-config",inputs:["disabled","function"]},{kind:"component",type:on,selector:"tb-math-function-autocomplete",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:an,decorators:[{type:n,args:[{selector:"tb-action-node-math-function-config",template:'
\n \n \n
\n tb.rulenode.argument-tile\n \n \n
\n
\n {{\'tb.rulenode.custom-expression-field-input\' | translate }} *\n \n \n \n tb.rulenode.custom-expression-field-input-required\n \n tb.rulenode.custom-expression-field-input-hint\n \n
\n
\n tb.rulenode.result-title\n
\n \n tb.rulenode.type-field-input\n \n \n {{ argumentTypeResultMap.get(mathFunctionConfigForm.get(\'result.type\').value)?.name | translate }}\n \n \n {{ argumentTypeResultMap.get(argument).name | translate }}\n \n {{ argumentTypeResultMap.get(argument).description }}\n \n \n \n \n tb.rulenode.type-field-input-required\n \n \n
\n \n tb.rulenode.attribute-scope-field-input\n \n \n {{ attributeScopeMap.get(scope) | translate }}\n \n \n \n \n tb.rulenode.key-field-input\n \n help\n \n tb.rulenode.key-field-input-required\n \n \n
\n
\n \n tb.rulenode.number-floating-point-field-input\n \n \n \n
\n
\n \n {{\'tb.rulenode.add-to-message-field-input\' | translate }}\n \n \n {{\'tb.rulenode.add-to-metadata-field-input\' | translate}}\n \n
\n
\n
\n
\n',styles:[":host ::ng-deep .fields-group{padding:0 16px 8px;margin:10px 0;border:1px groove rgba(0,0,0,.25);border-radius:4px}:host ::ng-deep .fields-group .mat-mdc-form-field .mat-mdc-form-field-infix{width:100%}:host ::ng-deep .fields-group legend{color:#000000b3;width:-moz-fit-content;width:fit-content}:host ::ng-deep .fields-group legend+*{display:block}:host ::ng-deep .fields-group legend+*.no-margin-top{margin-top:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ln extends b{set required(e){this.requiredValue!==e&&(this.requiredValue=e,this.updateValidators())}get required(){return this.requiredValue}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptSizing="fixed",this.searchText="",this.dirty=!1,this.messageTypes=["POST_ATTRIBUTES_REQUEST","POST_TELEMETRY_REQUEST"],this.propagateChange=e=>{},this.messageTypeFormGroup=this.fb.group({messageType:[null,[D.maxLength(255)]]})}registerOnTouched(e){}registerOnChange(e){this.propagateChange=e}ngOnInit(){this.outputMessageTypes=this.messageTypeFormGroup.get("messageType").valueChanges.pipe(he((e=>{this.updateView(e)})),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))))}writeValue(e){this.searchText="",this.modelValue=e,this.messageTypeFormGroup.get("messageType").patchValue(e,{emitEvent:!1}),this.dirty=!0}onFocus(){this.dirty&&(this.messageTypeFormGroup.get("messageType").updateValueAndValidity({onlySelf:!0,emitEvent:!0}),this.dirty=!1)}updateView(e){this.modelValue!==e&&(this.modelValue=e,this.propagateChange(this.modelValue))}displayMessageTypeFn(e){return e||void 0}fetchMessageTypes(e,t=!1){return this.searchText=e,qe(this.messageTypes).pipe(ve((n=>n.filter((n=>t?!!e&&n===e:!e||n.toUpperCase().startsWith(e.toUpperCase()))))))}clear(){this.messageTypeFormGroup.get("messageType").patchValue(null,{emitEvent:!0}),setTimeout((()=>{this.messageTypeInput.nativeElement.blur(),this.messageTypeInput.nativeElement.focus()}),0)}setDisabledState(e){e?this.messageTypeFormGroup.disable({emitEvent:!1}):this.messageTypeFormGroup.enable({emitEvent:!1})}updateValidators(){this.messageTypeFormGroup.get("messageType").setValidators(this.required?[D.required,D.maxLength(255)]:[D.maxLength(255)]),this.messageTypeFormGroup.get("messageType").updateValueAndValidity({emitEvent:!1})}}e("OutputMessageTypeAutocompleteComponent",ln),ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ln,selector:"tb-output-message-type-autocomplete",inputs:{autocompleteHint:"autocompleteHint",subscriptSizing:"subscriptSizing",required:"required"},providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],viewQueries:[{propertyName:"messageTypeInput",first:!0,predicate:["messageTypeInput"],descendants:!0,static:!0}],usesInheritance:!0,ngImport:t,template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],ln.prototype,"required",null),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ln,decorators:[{type:n,args:[{selector:"tb-output-message-type-autocomplete",providers:[{provide:P,useExisting:a((()=>ln)),multi:!0}],template:'\n {{\'tb.rulenode.output-message-type\' | translate}}\n \n \n \n \n \n \n \n {{autocompleteHint | translate}}\n \n {{ \'tb.rulenode.output-message-type-required\' | translate }}\n \n \n {{ \'tb.rulenode.output-message-type-max-length\' | translate }}\n \n\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{messageTypeInput:[{type:o,args:["messageTypeInput",{static:!0}]}],autocompleteHint:[{type:i}],subscriptSizing:[{type:i}],required:[{type:i}]}});class sn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.serviceType=p.TB_RULE_ENGINE,this.deduplicationStrategie=gt,this.deduplicationStrategies=Object.keys(this.deduplicationStrategie),this.deduplicationStrategiesTranslations=yt}configForm(){return this.deduplicationConfigForm}onConfigurationSet(e){this.deduplicationConfigForm=this.fb.group({interval:[X(e?.interval)?e.interval:null,[D.required,D.min(1)]],strategy:[X(e?.strategy)?e.strategy:null,[D.required]],outMsgType:[X(e?.outMsgType)?e.outMsgType:null,[D.required]],queueName:[X(e?.queueName)?e.queueName:null,[D.required]],maxPendingMsgs:[X(e?.maxPendingMsgs)?e.maxPendingMsgs:null,[D.required,D.min(1),D.max(1e3)]],maxRetries:[X(e?.maxRetries)?e.maxRetries:null,[D.required,D.min(0),D.max(100)]]})}updateValidators(e){this.deduplicationConfigForm.get("strategy").value===this.deduplicationStrategie.ALL?(this.deduplicationConfigForm.get("outMsgType").enable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").enable({emitEvent:!1})):(this.deduplicationConfigForm.get("outMsgType").disable({emitEvent:!1}),this.deduplicationConfigForm.get("queueName").disable({emitEvent:!1})),this.deduplicationConfigForm.get("outMsgType").updateValueAndValidity({emitEvent:e}),this.deduplicationConfigForm.get("queueName").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["strategy"]}}e("DeduplicationConfigComponent",sn),sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:sn,selector:"tb-action-node-msg-deduplication-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:J.QueueAutocompleteComponent,selector:"tb-queue-autocomplete",inputs:["labelText","requiredText","autocompleteHint","subscriptSizing","required","queueType","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ln,selector:"tb-output-message-type-autocomplete",inputs:["autocompleteHint","subscriptSizing","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sn,decorators:[{type:n,args:[{selector:"tb-action-node-msg-deduplication-config",template:"
\n \n {{'tb.rulenode.interval' | translate}}\n \n {{'tb.rulenode.interval-hint' | translate}}\n \n {{'tb.rulenode.interval-required' | translate}}\n \n \n {{'tb.rulenode.interval-min-error' | translate}}\n \n \n \n {{'tb.rulenode.strategy' | translate}}\n \n \n {{ deduplicationStrategiesTranslations.get(strategy) | translate }}\n \n \n \n {{'tb.rulenode.strategy-first-hint' | translate}}\n {{'tb.rulenode.strategy-last-hint' | translate}}\n \n {{'tb.rulenode.strategy-required' | translate}}\n \n \n
\n \n \n \n \n
\n \n \n \n
\n
Advanced settings
\n
\n
\n
\n \n \n {{'tb.rulenode.max-pending-msgs' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-hint' | translate}}\n \n {{'tb.rulenode.max-pending-msgs-required' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-max-error' | translate}}\n \n \n {{'tb.rulenode.max-pending-msgs-min-error' | translate}}\n \n \n \n {{'tb.rulenode.max-retries' | translate}}\n \n {{'tb.rulenode.max-retries-hint' | translate}}\n \n {{'tb.rulenode.max-retries-required' | translate}}\n \n \n {{'tb.rulenode.max-retries-max-error' | translate}}\n \n \n {{'tb.rulenode.max-retries-min-error' | translate}}\n \n \n \n
\n
\n",styles:[":host ::ng-deep .mat-expansion-panel.advanced-settings{border:none;box-shadow:none;padding:0}:host ::ng-deep .mat-expansion-panel.advanced-settings .mat-expansion-panel-body{padding:0}:host ::ng-deep .mat-expansion-panel:not(.mat-expanded) .mat-expansion-panel-header:not([aria-disabled=true]):hover{background:white}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class mn{}e("ExampleHintComponent",mn),mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,deps:[],target:t.ɵɵFactoryTarget.Component}),mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mn,selector:"tb-example-hint",inputs:{hintText:"hintText",popupHelpLink:"popupHelpLink"},ngImport:t,template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mn,decorators:[{type:n,args:[{selector:"tb-example-hint",template:'
\n
{{ hintText }}
\n
\n
\n
\n',styles:[":host .space-between{display:flex;justify-content:space-between;gap:20px}:host .space-between .see-example{display:flex;flex-shrink:0}\n"]}]}],propDecorators:{hintText:[{type:i}],popupHelpLink:[{type:i}]}});class un extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.uniqueKeyValuePairValidator=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),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")}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}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 n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));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:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}))}validate(e){const t=this.kvListFormGroup.get("keyVals").value;if(!t.length&&this.required)return{kvMapRequired:!0};if(!this.kvListFormGroup.valid)return{kvFieldsRequired:!0};if(this.uniqueKeyValuePairValidator)for(const e of t)if(e.key===e.value)return{uniqueKeyValuePair:!0};return null}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)}}}e("KvMapConfigComponent",un),un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:un,selector:"tb-kv-map-config",inputs:{disabled:"disabled",uniqueKeyValuePairValidator:"uniqueKeyValuePairValidator",labelText:"labelText",requiredText:"requiredText",keyText:"keyText",keyRequiredText:"keyRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],un.prototype,"disabled",void 0),Se([h()],un.prototype,"uniqueKeyValuePairValidator",void 0),Se([h()],un.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:un,decorators:[{type:n,args:[{selector:"tb-kv-map-config",providers:[{provide:P,useExisting:a((()=>un)),multi:!0},{provide:w,useExisting:a((()=>un)),multi:!0}],template:'
\n
\n
{{ labelText }}
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ keyText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],uniqueKeyValuePairValidator:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],keyText:[{type:i}],keyRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class pn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.entityType=x,this.propagateChange=null}ngOnInit(){this.deviceRelationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],relationType:[null],deviceTypes:[null,[D.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})}}e("DeviceRelationsQueryConfigComponent",pn),pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:pn,selector:"tb-device-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ee.EntitySubTypeListComponent,selector:"tb-entity-subtype-list",inputs:["required","floatLabel","label","disabled","entityType","emptyInputPlaceholder","filledInputPlaceholder","appearance","subscriptSizing","additionalClasses"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pn,decorators:[{type:n,args:[{selector:"tb-device-relations-query-config",providers:[{provide:P,useExisting:a((()=>pn)),multi:!0}],template:'
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n \n \n \n help\n \n
\n',styles:[":host .last-level-slide-toggle{margin:8px 0 24px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class dn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.values(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.required]],maxLevel:[null,[D.min(1)]],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})}}e("RelationsQueryConfigComponent",dn),dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:dn,selector:"tb-relations-query-config",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dn,decorators:[{type:n,args:[{selector:"tb-relations-query-config",providers:[{provide:P,useExisting:a((()=>dn)),multi:!0}],template:'
\n
tb.rulenode.relations-query
\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 {{ \'tb.rulenode.max-relation-level-error\' | translate }}\n \n \n
\n
\n \n {{ \'alias.last-level-relation\' | translate }}\n \n
\n
\n
\n
relation.relation-filters
\n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class cn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.truncate=n,this.fb=r,this.placeholder="tb.rulenode.add-message-type",this.separatorKeysCodes=[le,se,me],this.messageTypes=[],this.messageTypesList=[],this.searchText="",this.propagateChange=e=>{},this.messageTypeConfigForm=this.fb.group({messageType:[null]});for(const e of Object.keys(v))this.messageTypesList.push({name:C.get(v[e]),value:e})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnInit(){this.filteredMessageTypes=this.messageTypeConfigForm.get("messageType").valueChanges.pipe(Fe(""),ve((e=>e||"")),Ce((e=>this.fetchMessageTypes(e))),ke())}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&&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 qe(this.messageTypesList.filter((t=>t.name.toUpperCase().includes(e))))}return qe(this.messageTypesList)}transformMessageType(e){if((e||"").trim()){let t;const n=e.trim(),r=this.messageTypesList.find((e=>e.name===n));t=r?{name:r.name,value:r.value}:{name:n,value:n},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))}}e("MessageTypesConfigComponent",cn),cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,deps:[{token:G.Store},{token:H.TranslateService},{token:F.TruncatePipe},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),cn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:cn,selector:"tb-message-types-config",inputs:{required:"required",label:"label",placeholder:"placeholder",disabled:"disabled"},providers:[{provide:P,useExisting:a((()=>cn)),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:t,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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Te.MatAutocomplete,selector:"mat-autocomplete",inputs:["disableRipple","hideSingleSelectionIndicator"],exportAs:["matAutocomplete"]},{kind:"directive",type:Te.MatAutocompleteTrigger,selector:"input[matAutocomplete], textarea[matAutocomplete]",exportAs:["matAutocompleteTrigger"]},{kind:"directive",type:Te.MatAutocompleteOrigin,selector:"[matAutocompleteOrigin]",exportAs:["matAutocompleteOrigin"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:Ie.HighlightPipe,name:"highlight"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:cn,decorators:[{type:n,args:[{selector:"tb-message-types-config",providers:[{provide:P,useExisting:a((()=>cn)),multi:!0}],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 {{ \'tb.rulenode.no-message-type-matching\' | translate :\n {messageType: truncate.transform(searchText, true, 6, '...')}\n }}\n \n \n \n tb.rulenode.create-new-message-type\n \n
\n
\n
\n help\n \n {{ \'tb.rulenode.select-message-types-required\' | translate }}\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:F.TruncatePipe},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],label:[{type:i}],placeholder:[{type:i}],disabled:[{type:i}],chipList:[{type:o,args:["chipList",{static:!1}]}],matAutocomplete:[{type:o,args:["messageTypeAutocomplete",{static:!1}]}],messageTypeInput:[{type:o,args:["messageTypeInput",{static:!1}]}]}});class fn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.subscriptions=[],this.disableCertPemCredentials=!1,this.passwordFieldRequired=!0,this.allCredentialsTypes=Tt,this.credentialsTypeTranslationsMap=It,this.propagateChange=e=>{}}ngOnInit(){this.credentialsConfigFormGroup=this.fb.group({type:[null,[D.required]],username:[null,[]],password:[null,[]],caCert:[null,[]],caCertFileName:[null,[]],privateKey:[null,[]],privateKeyFileName:[null,[]],cert:[null,[]],certFileName:[null,[]]}),this.subscriptions.push(this.credentialsConfigFormGroup.valueChanges.subscribe((()=>{this.updateView()}))),this.subscriptions.push(this.credentialsConfigFormGroup.get("type").valueChanges.subscribe((()=>{this.credentialsTypeChanged()})))}ngOnChanges(e){for(const t of Object.keys(e)){const n=e[t];if(!n.firstChange&&n.currentValue!==n.previousValue&&n.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){X(e)&&(this.credentialsConfigFormGroup.reset(e,{emitEvent:!1}),this.updateValidators())}setDisabledState(e){e?this.credentialsConfigFormGroup.disable({emitEvent:!1}):(this.credentialsConfigFormGroup.enable({emitEvent:!1}),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([D.required]),this.credentialsConfigFormGroup.get("password").setValidators(this.passwordFieldRequired?[D.required]:[]);break;case"cert.PEM":this.credentialsConfigFormGroup.setValidators([this.requiredFilesSelected(D.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 n=>{t||(t=[Object.keys(n.controls)]);return n?.controls&&t.some((t=>t.every((t=>!e(n.controls[t])))))?null:{notAllRequiredFilesSelected:!0}}}}e("CredentialsConfigComponent",fn),fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:fn,selector:"tb-credentials-config",inputs:{required:"required",disableCertPemCredentials:"disableCertPemCredentials",passwordFieldRequired:"passwordFieldRequired"},providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],usesInheritance:!0,usesOnChanges:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:Ne.MatExpansionPanelContent,selector:"ng-template[matExpansionPanelContent]"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:fn,decorators:[{type:n,args:[{selector:"tb-credentials-config",providers:[{provide:P,useExisting:a((()=>fn)),multi:!0},{provide:w,useExisting:a((()=>fn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{required:[{type:i}],disableCertPemCredentials:[{type:i}],passwordFieldRequired:[{type:i}]}});class gn{constructor(e,t){this.fb=e,this.translate=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.selectOptions=[];for(const e of wt.keys())this.selectOptions.push({value:e,name:this.translate.instant(wt.get(e))})}ngOnInit(){this.chipControlGroup=this.fb.group({chipControl:[null,[]]}),this.chipControlGroup.get("chipControl").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e&&this.propagateChange(e)}))}writeValue(e){this.chipControlGroup.get("chipControl").patchValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){e?this.chipControlGroup.disable({emitEvent:!1}):this.chipControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("MsgMetadataChipComponent",gn),gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,deps:[{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),gn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:gn,selector:"tb-msg-metadata-chip",inputs:{labelText:"labelText"},providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],ngImport:t,template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:gn,decorators:[{type:n,args:[{selector:"tb-msg-metadata-chip",providers:[{provide:P,useExisting:a((()=>gn)),multi:!0}],template:'
\n
{{ labelText }}
\n \n {{ option.name }}\n \n
\n'}]}],ctorParameters:function(){return[{type:E.FormBuilder},{type:H.TranslateService}]},propDecorators:{labelText:[{type:i}]}});class yn extends b{constructor(e,t,n,r){super(e),this.store=e,this.translate=t,this.injector=n,this.fb=r,this.destroy$=new Ae,this.sourceFieldSubcritption=[],this.propagateChange=null,this.valueChangeSubscription=null,this.disabled=!1,this.required=!1}ngOnInit(){this.ngControl=this.injector.get(V),null!=this.ngControl&&(this.ngControl.valueAccessor=this),this.svListFormGroup=this.fb.group({}),this.svListFormGroup.addControl("keyVals",this.fb.array([]))}keyValsFormArray(){return this.svListFormGroup.get("keyVals")}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}setDisabledState(e){this.disabled=e,this.disabled?this.svListFormGroup.disable({emitEvent:!1}):this.svListFormGroup.enable({emitEvent:!1})}writeValue(e){this.valueChangeSubscription&&this.valueChangeSubscription.unsubscribe();const t=[];if(e)for(const n of Object.keys(e))Object.prototype.hasOwnProperty.call(e,n)&&t.push(this.fb.group({key:[n,[D.required]],value:[e[n],[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]}));this.svListFormGroup.setControl("keyVals",this.fb.array(t));for(const e of this.keyValsFormArray().controls)this.keyChangeSubscribe(e);this.valueChangeSubscription=this.svListFormGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((()=>{this.updateModel()}))}errorTrigger(){const e=this.keyValsFormArray();for(const t of e.controls)for(const e of Object.keys(t.value))if(t.get(e).touched&&t.get(e).invalid)return!0;return!1}filterSelectOptions(e){const t=[];for(const e of this.svListFormGroup.get("keyVals").value){const n=this.selectOptions.find((t=>t.value===e.key));n&&t.push(n)}const n=[];for(const r of this.selectOptions)X(t.find((e=>e.value===r.value)))&&r.value!==e?.get("key").value||n.push(r);return n}removeKeyVal(e){this.svListFormGroup.get("keyVals").removeAt(e),this.sourceFieldSubcritption[e].unsubscribe(),this.sourceFieldSubcritption.splice(e,1)}addKeyVal(){const e=this.svListFormGroup.get("keyVals");e.push(this.fb.group({key:["",[D.required]],value:["",[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]]})),this.keyChangeSubscribe(e.at(e.length-1))}keyChangeSubscribe(e){this.sourceFieldSubcritption.push(e.get("key").valueChanges.pipe(Le(this.destroy$)).subscribe((t=>{e.get("value").patchValue(this.targetKeyPrefix+t[0].toUpperCase()+t.slice(1))})))}validate(e){return!this.svListFormGroup.get("keyVals").value.length&&this.required?{svMapRequired:!0}:this.svListFormGroup.valid?null:{svFieldsRequired:!0}}updateModel(){const e=this.svListFormGroup.get("keyVals").value;if(this.required&&!e.length||!this.svListFormGroup.valid)this.propagateChange(null);else{const t={};e.forEach((e=>{t[e.key]=e.value})),this.propagateChange(t)}}}e("SvMapConfigComponent",yn),yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,deps:[{token:G.Store},{token:H.TranslateService},{token:t.Injector},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:yn,selector:"tb-sv-map-config",inputs:{selectOptions:"selectOptions",disabled:"disabled",labelText:"labelText",requiredText:"requiredText",targetKeyPrefix:"targetKeyPrefix",selectText:"selectText",selectRequiredText:"selectRequiredText",valText:"valText",valRequiredText:"valRequiredText",hintText:"hintText",popupHelpLink:"popupHelpLink",required:"required"},providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgClass,selector:"[ngClass]",inputs:["class","ngClass"]},{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:ye.DefaultClassDirective,selector:" [ngClass], [ngClass.xs], [ngClass.sm], [ngClass.md], [ngClass.lg], [ngClass.xl], [ngClass.lt-sm], [ngClass.lt-md], [ngClass.lt-lg], [ngClass.lt-xl], [ngClass.gt-xs], [ngClass.gt-sm], [ngClass.gt-md], [ngClass.gt-lg]",inputs:["ngClass","ngClass.xs","ngClass.sm","ngClass.md","ngClass.lg","ngClass.xl","ngClass.lt-sm","ngClass.lt-md","ngClass.lt-lg","ngClass.lt-xl","ngClass.gt-xs","ngClass.gt-sm","ngClass.gt-md","ngClass.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormControlDirective,selector:"[formControl]",inputs:["formControl","disabled","ngModel"],outputs:["ngModelChange"],exportAs:["ngForm"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:R.AsyncPipe,name:"async"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),Se([h()],yn.prototype,"disabled",void 0),Se([h()],yn.prototype,"required",void 0),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:yn,decorators:[{type:n,args:[{selector:"tb-sv-map-config",providers:[{provide:P,useExisting:a((()=>yn)),multi:!0},{provide:w,useExisting:a((()=>yn)),multi:!0}],template:'
\n
\n
tb.rulenode.originator-fields-mapping
\n
\n tb.rulenode.map-fields-required\n
\n
\n
\n
\n
\n
{{ selectText }}
\n
{{ valText }}
\n
\n
\n
\n
\n \n \n \n {{option.name}}\n \n \n \n \n \n \n
\n \n
\n
\n
\n
\n
\n
\n \n
\n \n
\n',styles:[":host .field-space{flex:1 1 50%}:host .actions-header{width:40px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:t.Injector},{type:E.FormBuilder}]},propDecorators:{selectOptions:[{type:i}],disabled:[{type:i}],labelText:[{type:i}],requiredText:[{type:i}],targetKeyPrefix:[{type:i}],selectText:[{type:i}],selectRequiredText:[{type:i}],valText:[{type:i}],valRequiredText:[{type:i}],hintText:[{type:i}],popupHelpLink:[{type:i}],required:[{type:i}]}});class xn extends b{get required(){return this.requiredValue}set required(e){this.requiredValue=fe(e)}constructor(e,t){super(e),this.store=e,this.fb=t,this.directionTypes=Object.keys(g),this.directionTypeTranslations=y,this.propagateChange=null}ngOnInit(){this.relationsQueryFormGroup=this.fb.group({fetchLastLevelOnly:[!1,[]],direction:[null,[D.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})}}e("RelationsQueryConfigOldComponent",xn),xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:xn,selector:"tb-relations-query-config-old",inputs:{disabled:"disabled",required:"required"},providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Ve.RelationFiltersComponent,selector:"tb-relation-filters",inputs:["disabled","allowedEntityTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:xn,decorators:[{type:n,args:[{selector:"tb-relations-query-config-old",providers:[{provide:P,useExisting:a((()=>xn)),multi:!0}],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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]},propDecorators:{disabled:[{type:i}],required:[{type:i}]}});class bn{constructor(e,t){this.translate=e,this.fb=t,this.propagateChange=e=>{},this.destroy$=new Ae,this.separatorKeysCodes=[le,se,me],this.onTouched=()=>{}}ngOnInit(){this.attributeControlGroup=this.fb.group({clientAttributeNames:[null,[]],sharedAttributeNames:[null,[]],serverAttributeNames:[null,[]],latestTsKeyNames:[null,[]],getLatestValueWithTs:[!1,[]]},{validators:this.atLeastOne(D.required,["clientAttributeNames","sharedAttributeNames","serverAttributeNames","latestTsKeyNames"])}),this.attributeControlGroup.valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}validate(){return this.attributeControlGroup.valid?null:{atLeastOneRequired:!0}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}writeValue(e){this.attributeControlGroup.setValue(e,{emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){this.onTouched=e}setDisabledState(e){e?this.attributeControlGroup.disable({emitEvent:!1}):this.attributeControlGroup.enable({emitEvent:!1})}ngOnDestroy(){this.destroy$.next(null),this.destroy$.complete()}}e("SelectAttributesComponent",bn),bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,deps:[{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:bn,selector:"tb-select-attributes",inputs:{popupHelpLink:"popupHelpLink"},providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],ngImport:t,template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgTemplateOutlet,selector:"[ngTemplateOutlet]",inputs:["ngTemplateOutletContext","ngTemplateOutlet","ngTemplateOutletInjector"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:bn,decorators:[{type:n,args:[{selector:"tb-select-attributes",providers:[{provide:P,useExisting:a((()=>bn)),multi:!0},{provide:w,useExisting:bn,multi:!0}],template:'
\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n \n {{ \'tb.rulenode.fetch-latest-telemetry-with-timestamp\' | translate }}\n \n
\n
\n\n\n help\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:H.TranslateService},{type:E.FormBuilder}]},propDecorators:{popupHelpLink:[{type:i}]}});class hn extends b{constructor(e,t){super(e),this.store=e,this.fb=t,this.propagateChange=null,this.destroy$=new Ae,this.alarmStatus=k,this.alarmStatusTranslations=L}ngOnInit(){this.alarmStatusGroup=this.fb.group({alarmStatus:[null,[]]}),this.alarmStatusGroup.get("alarmStatus").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{this.propagateChange(e)}))}setDisabledState(e){e?this.alarmStatusGroup.disable({emitEvent:!1}):this.alarmStatusGroup.enable({emitEvent:!1})}registerOnChange(e){this.propagateChange=e}registerOnTouched(e){}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}writeValue(e){this.alarmStatusGroup.get("alarmStatus").patchValue(e,{emitEvent:!1})}}e("AlarmStatusSelectComponent",hn),hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:hn,selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"],dependencies:[{kind:"component",type:ue.MatChipListbox,selector:"mat-chip-listbox",inputs:["tabIndex","multiple","aria-orientation","selectable","compareWith","required","hideSingleSelectionIndicator","value"],outputs:["change"]},{kind:"component",type:ue.MatChipOption,selector:"mat-basic-chip-option, [mat-basic-chip-option], mat-chip-option, [mat-chip-option]",inputs:["color","disabled","disableRipple","tabIndex","selectable","selected"],outputs:["selectionChange"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:hn,decorators:[{type:n,args:[{selector:"tb-alarm-status-select",providers:[{provide:P,useExisting:a((()=>hn)),multi:!0}],template:'
\n \n
\n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_ACK) | translate }}\n \n
\n
\n \n {{ alarmStatusTranslations.get(alarmStatus.CLEARED_UNACK) | translate }}\n \n \n {{ alarmStatusTranslations.get(alarmStatus.ACTIVE_UNACK) | translate }}\n \n
\n
\n
\n',styles:[":host .chip-listbox{max-width:460px;width:100%}:host .chip-listbox .toggle-column{display:flex;flex:1 1 100%;gap:8px}:host .chip-listbox .option{margin:0}@media screen and (max-width: 959px){:host .chip-listbox{max-width:360px}:host .chip-listbox .toggle-column{flex-direction:column}}:host ::ng-deep .chip-listbox .mdc-evolution-chip-set__chips{gap:8px}:host ::ng-deep .chip-listbox .option button{flex-basis:100%;justify-content:start}:host ::ng-deep .chip-listbox .option .mdc-evolution-chip__graphic{flex-grow:0}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class vn{}e("RulenodeCoreConfigCommonModule",vn),vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),vn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:vn,declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}),vn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,imports:[O,T,Me]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:vn,decorators:[{type:l,args:[{declarations:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn],imports:[O,T,Me],exports:[un,pn,dn,cn,fn,rn,on,ln,Xt,gn,yn,xn,bn,hn,mn]}]}]});class Cn{}e("RuleNodeCoreConfigActionModule",Cn),Cn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Cn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Cn,declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}),Cn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Cn,decorators:[{type:l,args:[{declarations:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn],imports:[O,T,Me,vn],exports:[nn,We,en,Wt,zt,Ye,Ze,et,tt,Qt,nt,ot,Ht,jt,Yt,Zt,tn,Xe,rt,Jt,$t,an,sn]}]}]});class Fn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me]}configForm(){return this.calculateDeltaConfigForm}onConfigurationSet(e){this.calculateDeltaConfigForm=this.fb.group({inputValueKey:[e.inputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],outputValueKey:[e.outputValueKey,[D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]],useCache:[e.useCache,[]],addPeriodBetweenMsgs:[e.addPeriodBetweenMsgs,[]],periodValueKey:[e.periodValueKey,[]],round:[e.round,[D.min(0),D.max(15)]],tellFailureIfDeltaIsNegative:[e.tellFailureIfDeltaIsNegative,[]]})}prepareInputConfig(e){return{inputValueKey:X(e?.inputValueKey)?e.inputValueKey:null,outputValueKey:X(e?.outputValueKey)?e.outputValueKey:null,useCache:!X(e?.useCache)||e.useCache,addPeriodBetweenMsgs:!!X(e?.addPeriodBetweenMsgs)&&e.addPeriodBetweenMsgs,periodValueKey:X(e?.periodValueKey)?e.periodValueKey:null,round:X(e?.round)?e.round:null,tellFailureIfDeltaIsNegative:!X(e?.tellFailureIfDeltaIsNegative)||e.tellFailureIfDeltaIsNegative}}prepareOutputConfig(e){return Z(e)}updateValidators(e){this.calculateDeltaConfigForm.get("addPeriodBetweenMsgs").value?this.calculateDeltaConfigForm.get("periodValueKey").setValidators([D.required]):this.calculateDeltaConfigForm.get("periodValueKey").setValidators([]),this.calculateDeltaConfigForm.get("periodValueKey").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["addPeriodBetweenMsgs"]}}e("CalculateDeltaConfigComponent",Fn),Fn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Fn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Fn,selector:"tb-enrichment-node-calculate-delta-config",usesInheritance:!0,ngImport:t,template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Fn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-calculate-delta-config",template:"
\n
\n \n {{ 'tb.rulenode.input-value-key' | translate }}\n \n \n {{ 'tb.rulenode.input-value-key-required' | translate }}\n \n \n \n {{ 'tb.rulenode.output-value-key' | translate }}\n \n \n {{ 'tb.rulenode.output-value-key-required' | translate }}\n \n \n
\n \n {{ 'tb.rulenode.number-of-digits-after-floating-point' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n {{ 'tb.rulenode.number-of-digits-after-floating-point-range' | translate }}\n \n \n
\n
\n \n {{ 'tb.rulenode.failure-if-delta-negative' | translate }}\n \n
\n
\n \n {{ 'tb.rulenode.use-caching' | translate }}\n \n
\n
\n
\n \n {{ 'tb.rulenode.add-time-difference-between-readings' | translate:\n { inputValueKey: calculateDeltaConfigForm.get('inputValueKey').valid ?\n calculateDeltaConfigForm.get('inputValueKey').value : 'tb.rulenode.input-value-key' | translate } }}\n \n
\n \n {{ 'tb.rulenode.period-value-key' | translate }}\n \n \n {{ 'tb.rulenode.period-value-key-required' | translate }}\n \n \n
\n
\n
\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class kn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.customerAttributesConfigForm}prepareOutputConfig(e){const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,Z(e)}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.customerAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.customerAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo]})}}e("CustomerAttributesConfigComponent",kn),kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:kn,selector:"tb-enrichment-node-customer-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:kn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-customer-attributes-config",template:'
\n
tb.rulenode.mapping-of-customers-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Ln extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.deviceAttributesConfigForm}onConfigurationSet(e){this.deviceAttributesConfigForm=this.fb.group({deviceRelationsQuery:[e.deviceRelationsQuery,[D.required]],tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{deviceRelationsQuery:X(e?.deviceRelationsQuery)?e.deviceRelationsQuery:null,tellFailureIfAbsent:!X(e?.tellFailureIfAbsent)||e.tellFailureIfAbsent,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,attributesControl:e?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("DeviceAttributesConfigComponent",Ln),Ln.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Ln.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Ln,selector:"tb-enrichment-node-device-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:pn,selector:"tb-device-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Ln,decorators:[{type:n,args:[{selector:"tb-enrichment-node-device-attributes-config",template:'
\n
\n
tb.rulenode.device-relations-query
\n \n \n
\n
\n
\n
tb.rulenode.related-device-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Tn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.predefinedValues=[];for(const e of Object.keys(ct))this.predefinedValues.push({value:ct[e],name:this.translate.instant(ft.get(ct[e]))})}ngOnInit(){super.ngOnInit()}configForm(){return this.entityDetailsConfigForm}prepareInputConfig(e){let t;return t=X(e?.addToMetadata)?e.addToMetadata?Pt.METADATA:Pt.DATA:e?.fetchTo?e.fetchTo:Pt.DATA,{detailsList:X(e?.detailsList)?e.detailsList:null,fetchTo:t}}onConfigurationSet(e){this.entityDetailsConfigForm=this.fb.group({detailsList:[e.detailsList,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("EntityDetailsConfigComponent",Tn),Tn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Tn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Tn,selector:"tb-enrichment-node-entity-details-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Tn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-entity-details-config",template:'
\n \n \n help\n \n \n \n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class In extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n,this.separatorKeysCodes=[le,se,me],this.aggregationTypes=I,this.aggregations=Object.values(I),this.aggregationTypesTranslations=N,this.fetchMode=gt,this.samplingOrders=Object.values(bt),this.samplingOrdersTranslate=Ft,this.timeUnits=Object.values(mt),this.timeUnitsTranslationMap=ut,this.deduplicationStrategiesHintTranslations=xt,this.headerOptions=[],this.timeUnitMap={[mt.MILLISECONDS]:1,[mt.SECONDS]:1e3,[mt.MINUTES]:6e4,[mt.HOURS]:36e5,[mt.DAYS]:864e5},this.intervalValidator=()=>e=>e.get("startInterval").value*this.timeUnitMap[e.get("startIntervalTimeUnit").value]<=e.get("endInterval").value*this.timeUnitMap[e.get("endIntervalTimeUnit").value]?{intervalError:!0}:null;for(const e of yt.keys())this.headerOptions.push({value:e,name:this.translate.instant(yt.get(e))})}configForm(){return this.getTelemetryFromDatabaseConfigForm}onConfigurationSet(e){this.getTelemetryFromDatabaseConfigForm=this.fb.group({latestTsKeyNames:[e.latestTsKeyNames,[D.required]],aggregation:[e.aggregation,[D.required]],fetchMode:[e.fetchMode,[D.required]],orderBy:[e.orderBy,[]],limit:[e.limit,[]],useMetadataIntervalPatterns:[e.useMetadataIntervalPatterns,[]],interval:this.fb.group({startInterval:[e.interval.startInterval,[]],startIntervalTimeUnit:[e.interval.startIntervalTimeUnit,[]],endInterval:[e.interval.endInterval,[]],endIntervalTimeUnit:[e.interval.endIntervalTimeUnit,[]]}),startIntervalPattern:[e.startIntervalPattern,[]],endIntervalPattern:[e.endIntervalPattern,[]]})}validatorTriggers(){return["fetchMode","useMetadataIntervalPatterns"]}toggleChange(e){this.getTelemetryFromDatabaseConfigForm.get("fetchMode").patchValue(e,{emitEvent:!0})}prepareOutputConfig(e){return e.startInterval=e.interval.startInterval,e.startIntervalTimeUnit=e.interval.startIntervalTimeUnit,e.endInterval=e.interval.endInterval,e.endIntervalTimeUnit=e.interval.endIntervalTimeUnit,delete e.interval,Z(e)}prepareInputConfig(e){return ee(e)&&(e.interval={startInterval:e.startInterval,startIntervalTimeUnit:e.startIntervalTimeUnit,endInterval:e.endInterval,endIntervalTimeUnit:e.endIntervalTimeUnit}),{latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,aggregation:X(e?.aggregation)?e.aggregation:I.NONE,fetchMode:X(e?.fetchMode)?e.fetchMode:gt.FIRST,orderBy:X(e?.orderBy)?e.orderBy:bt.ASC,limit:X(e?.limit)?e.limit:1e3,useMetadataIntervalPatterns:!!X(e?.useMetadataIntervalPatterns)&&e.useMetadataIntervalPatterns,interval:{startInterval:X(e?.interval?.startInterval)?e.interval.startInterval:2,startIntervalTimeUnit:X(e?.interval?.startIntervalTimeUnit)?e.interval.startIntervalTimeUnit:mt.MINUTES,endInterval:X(e?.interval?.endInterval)?e.interval.endInterval:1,endIntervalTimeUnit:X(e?.interval?.endIntervalTimeUnit)?e.interval.endIntervalTimeUnit:mt.MINUTES},startIntervalPattern:X(e?.startIntervalPattern)?e.startIntervalPattern:null,endIntervalPattern:X(e?.endIntervalPattern)?e.endIntervalPattern:null}}updateValidators(e){const t=this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value,n=this.getTelemetryFromDatabaseConfigForm.get("useMetadataIntervalPatterns").value;t&&t===gt.ALL?(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([D.required,D.min(2),D.max(1e3)])):(this.getTelemetryFromDatabaseConfigForm.get("aggregation").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("orderBy").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("limit").setValidators([])),n?(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([]),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)]),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").setValidators([D.required,D.pattern(/(?:.|\s)*\S(&:.|\s)*/)])):(this.getTelemetryFromDatabaseConfigForm.get("interval.startInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").setValidators([D.required,D.min(1),D.max(2147483647)]),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").setValidators([D.required]),this.getTelemetryFromDatabaseConfigForm.get("interval").setValidators([this.intervalValidator()]),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("interval.startInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.startIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endInterval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval.endIntervalTimeUnit").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("interval").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("startIntervalPattern").updateValueAndValidity({emitEvent:e}),this.getTelemetryFromDatabaseConfigForm.get("endIntervalPattern").updateValueAndValidity({emitEvent:e})}removeKey(e,t){const n=this.getTelemetryFromDatabaseConfigForm.get(t).value,r=n.indexOf(e);r>=0&&(n.splice(r,1),this.getTelemetryFromDatabaseConfigForm.get(t).setValue(n,{emitEvent:!0}))}clearChipGrid(){this.getTelemetryFromDatabaseConfigForm.get("latestTsKeyNames").patchValue([],{emitEvent:!0})}addKey(e,t){const n=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}))}n&&(n.value="")}defaultPaddingEnable(){return this.getTelemetryFromDatabaseConfigForm.get("fetchMode").value===gt.ALL&&this.getTelemetryFromDatabaseConfigForm.get("aggregation").value===I.NONE}}e("GetTelemetryFromDatabaseConfigComponent",In),In.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),In.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:In,selector:"tb-enrichment-node-get-telemetry-from-database",usesInheritance:!0,ngImport:t,template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Ge.HelpPopupComponent,selector:"[tb-help-popup], [tb-help-popup-content]",inputs:["tb-help-popup","tb-help-popup-content","trigger-text","trigger-style","tb-help-popup-placement","tb-help-popup-style","hintMode"]},{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:mn,selector:"tb-example-hint",inputs:["hintText","popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:In,decorators:[{type:n,args:[{selector:"tb-enrichment-node-get-telemetry-from-database",template:'
\n \n
\n help\n \n
\n
\n
tb.rulenode.fetch-interval
\n
\n \n {{ \'tb.rulenode.use-metadata-dynamic-interval\' | translate }}\n \n
\n
\n
\n \n {{ \'tb.rulenode.interval-start\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n \n {{ \'tb.rulenode.interval-end\' | translate }}\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.time-unit\' | translate }}\n \n \n {{ timeUnitsTranslationMap.get(timeUnit) | translate }}\n \n \n \n
\n
\n error_outline\n
\n \n {{ \'tb.rulenode.fetch-timeseries-from-to\' | translate:\n {\n startInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.startInterval\').value,\n endInterval: getTelemetryFromDatabaseConfigForm.get(\'interval.endInterval\').value,\n startIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.startIntervalTimeUnit\').value.toLowerCase(),\n endIntervalTimeUnit: getTelemetryFromDatabaseConfigForm.get(\'interval.endIntervalTimeUnit\').value.toLowerCase()\n } }}\n \n \n {{ "tb.rulenode.fetch-timeseries-from-to-invalid" | translate }}\n \n
\n
\n
\n \n
\n \n {{ \'tb.rulenode.start-interval\' | translate }}\n \n \n {{ \'tb.rulenode.start-interval-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.end-interval\' | translate }}\n \n \n {{ \'tb.rulenode.end-interval-required\' | translate }}\n \n \n \n \n
\n
\n
\n
\n
tb.rulenode.fetch-strategy
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n {{ deduplicationStrategiesHintTranslations.get(getTelemetryFromDatabaseConfigForm.get(\'fetchMode\').value) | translate }}\n
\n
\n
\n \n {{ \'aggregation.function\' | translate }}\n \n \n {{ aggregationTypesTranslations.get(aggregationTypes[aggregation]) | translate }}\n \n \n \n
\n \n {{ "tb.rulenode.order-by-timestamp" | translate }} \n \n \n {{ samplingOrdersTranslate.get(order) | translate }}\n \n \n \n \n {{ "tb.rulenode.limit" | translate }}\n \n {{ "tb.rulenode.limit-hint" | translate }}\n \n {{ \'tb.rulenode.limit-required\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n {{ \'tb.rulenode.limit-range\' | translate }}\n \n \n
\n
\n
\n
\n',styles:[":host .see-example{display:inline-block}:host .description-block{display:flex;align-items:center;border-radius:6px;border:1px solid #EAEAEA}:host .description-block .description-icon{font-size:24px;height:24px;min-height:24px;width:24px;min-width:24px;line-height:24px;color:#d9d9d9;margin:4px}:host .description-block .description-text{font-size:12px;line-height:16px;letter-spacing:.25px;margin:6px}:host .description-block.error{color:var(--mdc-theme-error, #f44336)}:host .description-block.error .description-icon{color:var(--mdc-theme-error, #f44336)}:host .item-center{align-items:center}:host .item-center .fetch-mod-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Nn extends s{constructor(e,t,n){super(e),this.store=e,this.translate=t,this.fb=n}configForm(){return this.originatorAttributesConfigForm}onConfigurationSet(e){this.originatorAttributesConfigForm=this.fb.group({tellFailureIfAbsent:[e.tellFailureIfAbsent,[]],fetchTo:[e.fetchTo,[]],attributesControl:[e.attributesControl,[]]})}prepareInputConfig(e){return ee(e)&&(e.attributesControl={clientAttributeNames:X(e?.clientAttributeNames)?e.clientAttributeNames:null,latestTsKeyNames:X(e?.latestTsKeyNames)?e.latestTsKeyNames:null,serverAttributeNames:X(e?.serverAttributeNames)?e.serverAttributeNames:null,sharedAttributeNames:X(e?.sharedAttributeNames)?e.sharedAttributeNames:null,getLatestValueWithTs:!!X(e?.getLatestValueWithTs)&&e.getLatestValueWithTs}),{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA,tellFailureIfAbsent:!!X(e?.tellFailureIfAbsent)&&e.tellFailureIfAbsent,attributesControl:X(e?.attributesControl)?e.attributesControl:null}}prepareOutputConfig(e){for(const t of Object.keys(e.attributesControl))e[t]=e.attributesControl[t];return delete e.attributesControl,e}}e("OriginatorAttributesConfigComponent",Nn),Nn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,deps:[{token:G.Store},{token:H.TranslateService},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Nn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Nn,selector:"tb-enrichment-node-originator-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:bn,selector:"tb-select-attributes",inputs:["popupHelpLink"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Nn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-attributes-config",template:'
\n
\n
\n
tb.rulenode.originator-attributes
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n \n \n \n
\n
\n \n {{ \'tb.rulenode.tell-failure\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:H.TranslateService},{type:E.FormBuilder}]}});class Sn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.originatorFields=[];for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)})}configForm(){return this.originatorFieldsConfigForm}prepareOutputConfig(e){return Z(e)}prepareInputConfig(e){return{dataMapping:X(e?.dataMapping)?e.dataMapping:null,ignoreNullStrings:X(e?.ignoreNullStrings)?e.ignoreNullStrings:null,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.originatorFieldsConfigForm=this.fb.group({dataMapping:[e.dataMapping,[D.required]],ignoreNullStrings:[e.ignoreNullStrings,[]],fetchTo:[e.fetchTo,[]]})}}e("OriginatorFieldsConfigComponent",Sn),Sn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Sn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Sn,selector:"tb-enrichment-node-originator-fields-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n',dependencies:[{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Sn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-originator-fields-config",template:'
\n \n \n \n \n
\n \n {{ \'tb.rulenode.skip-empty-fields\' | translate }}\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class qn extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.DataToFetch=ht,this.msgMetadataLabelTranslations=Ct,this.originatorFields=[],this.fetchToData=[],this.destroy$=new Ae;for(const e of Object.keys(S))this.originatorFields.push({value:S[e].value,name:this.translate.instant(S[e].name)});for(const e of vt.keys())this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.relatedAttributesConfigForm}prepareOutputConfig(e){e.dataToFetch===ht.FIELDS?(e.dataMapping=e.svMap,delete e.svMap):(e.dataMapping=e.kvMap,delete e.kvMap);const t={};for(const n of Object.keys(e.dataMapping))t[n.trim()]=e.dataMapping[n];return e.dataMapping=t,delete e.svMap,delete e.kvMap,Z(e)}prepareInputConfig(e){let t,n,r={[S.name.value]:`relatedEntity${this.translate.instant(S.name.name)}`},o={serialNumber:"sn"};return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,t===ht.FIELDS?r=n:o=n,{relationsQuery:X(e?.relationsQuery)?e.relationsQuery:null,dataToFetch:t,svMap:r,kvMap:o,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.relatedAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.relatedAttributesConfigForm=this.fb.group({relationsQuery:[e.relationsQuery,[D.required]],dataToFetch:[e.dataToFetch,[]],kvMap:[e.kvMap,[]],svMap:[e.svMap,[]],fetchTo:[e.fetchTo,[]]}),this.relatedAttributesConfigForm.get("dataToFetch").valueChanges.pipe(Le(this.destroy$)).subscribe((e=>{e===ht.FIELDS?(this.relatedAttributesConfigForm.get("svMap").setValidators(D.required),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("kvMap").clearValidators(),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity()):(this.relatedAttributesConfigForm.get("kvMap").setValidators(D.required),this.relatedAttributesConfigForm.get("kvMap").updateValueAndValidity(),this.relatedAttributesConfigForm.get("svMap").clearValidators(),this.relatedAttributesConfigForm.get("svMap").updateValueAndValidity())}))}ngOnDestroy(){this.destroy$.next(),this.destroy$.complete()}}e("RelatedAttributesConfigComponent",qn),qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:qn,selector:"tb-enrichment-node-related-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:dn,selector:"tb-relations-query-config",inputs:["disabled","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"component",type:yn,selector:"tb-sv-map-config",inputs:["selectOptions","disabled","labelText","requiredText","targetKeyPrefix","selectText","selectRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:qn,decorators:[{type:n,args:[{selector:"tb-enrichment-node-related-attributes-config",template:'
\n \n \n
\n
tb.rulenode.data-to-fetch
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n \n \n \n \n
\n
\n',styles:[":host .toggle-block{display:flex;place-content:center}:host .toggle-block .fetch-to-data-toggle{max-width:630px;width:100%}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class An extends s{constructor(e,t,n){super(e),this.store=e,this.fb=t,this.translate=n,this.fetchToData=[],this.DataToFetch=ht;for(const e of vt.keys())e!==ht.FIELDS&&this.fetchToData.push({value:e,name:this.translate.instant(vt.get(e))})}configForm(){return this.tenantAttributesConfigForm}prepareInputConfig(e){let t,n;return t=X(e?.telemetry)?e.telemetry?ht.LATEST_TELEMETRY:ht.ATTRIBUTES:X(e?.dataToFetch)?e.dataToFetch:ht.ATTRIBUTES,n=X(e?.attrMapping)?e.attrMapping:X(e?.dataMapping)?e.dataMapping:null,{dataToFetch:t,dataMapping:n,fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}selectTranslation(e,t){return this.tenantAttributesConfigForm.get("dataToFetch").value===ht.LATEST_TELEMETRY?e:t}onConfigurationSet(e){this.tenantAttributesConfigForm=this.fb.group({dataToFetch:[e.dataToFetch,[]],dataMapping:[e.dataMapping,[D.required]],fetchTo:[e.fetchTo,[]]})}}e("TenantAttributesConfigComponent",An),An.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,deps:[{token:G.Store},{token:E.FormBuilder},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),An.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:An,selector:"tb-enrichment-node-tenant-attributes-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"directive",type:Oe.ToggleOption,selector:"tb-toggle-option",inputs:["value"]},{kind:"component",type:Be.ToggleSelectComponent,selector:"tb-toggle-select",inputs:["disabled","selectMediaBreakpoint","appearance","disablePagination"]},{kind:"component",type:un,selector:"tb-kv-map-config",inputs:["disabled","uniqueKeyValuePairValidator","labelText","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","popupHelpLink","required"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:An,decorators:[{type:n,args:[{selector:"tb-enrichment-node-tenant-attributes-config",template:'
\n
tb.rulenode.mapping-of-tenant-fields
\n
\n
\n \n \n {{ data.name }}\n \n \n
\n
\n \n \n \n \n
\n',styles:[":host .fetch-to-data-toggle{max-width:420px;width:100%}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder},{type:H.TranslateService}]}});class Mn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.fetchDeviceCredentialsConfigForm}prepareInputConfig(e){return{fetchTo:X(e?.fetchTo)?e.fetchTo:Pt.METADATA}}onConfigurationSet(e){this.fetchDeviceCredentialsConfigForm=this.fb.group({fetchTo:[e.fetchTo,[]]})}}e("FetchDeviceCredentialsConfigComponent",Mn),Mn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Mn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Mn,selector:"./tb-enrichment-node-fetch-device-credentials-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:gn,selector:"tb-msg-metadata-chip",inputs:["labelText"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Mn,decorators:[{type:n,args:[{selector:"./tb-enrichment-node-fetch-device-credentials-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Gn{}e("RulenodeCoreConfigEnrichmentModule",Gn),Gn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),Gn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:Gn,declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}),Gn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Gn,decorators:[{type:l,args:[{declarations:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn],imports:[O,T,vn],exports:[kn,Tn,Ln,Nn,Sn,In,qn,An,Fn,Mn]}]}]});class En extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.allAzureIotHubCredentialsTypes=Nt,this.azureIotHubCredentialsTypeTranslationsMap=St}configForm(){return this.azureIotHubConfigForm}onConfigurationSet(e){this.azureIotHubConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[D.required]],cleanSession:[!!e&&e.cleanSession,[]],ssl:[!!e&&e.ssl,[]],credentials:this.fb.group({type:[e&&e.credentials?e.credentials.type:null,[D.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"),n=t.get("type").value;switch(e&&t.reset({type:n},{emitEvent:!1}),t.get("sasKey").setValidators([]),t.get("privateKey").setValidators([]),t.get("privateKeyFileName").setValidators([]),t.get("cert").setValidators([]),t.get("certFileName").setValidators([]),n){case"sas":t.get("sasKey").setValidators([D.required]);break;case"cert.PEM":t.get("privateKey").setValidators([D.required]),t.get("privateKeyFileName").setValidators([D.required]),t.get("cert").setValidators([D.required]),t.get("certFileName").setValidators([D.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("AzureIotHubConfigComponent",En),En.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),En.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:En,selector:"tb-external-node-azure-iot-hub-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:R.NgSwitch,selector:"[ngSwitch]",inputs:["ngSwitch"]},{kind:"directive",type:R.NgSwitchCase,selector:"[ngSwitchCase]",inputs:["ngSwitchCase"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:Ne.MatAccordion,selector:"mat-accordion",inputs:["multi","hideToggle","displayMode","togglePosition"],exportAs:["matAccordion"]},{kind:"component",type:Ne.MatExpansionPanel,selector:"mat-expansion-panel",inputs:["disabled","expanded","hideToggle","togglePosition"],outputs:["opened","closed","expandedChange","afterExpand","afterCollapse"],exportAs:["matExpansionPanel"]},{kind:"component",type:Ne.MatExpansionPanelHeader,selector:"mat-expansion-panel-header",inputs:["tabIndex","expandedHeight","collapsedHeight"]},{kind:"directive",type:Ne.MatExpansionPanelTitle,selector:"mat-panel-title"},{kind:"directive",type:Ne.MatExpansionPanelDescription,selector:"mat-panel-description"},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:E.FormGroupName,selector:"[formGroupName]",inputs:["formGroupName"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:En,decorators:[{type:n,args:[{selector:"tb-external-node-azure-iot-hub-config",template:'
\n \n tb.rulenode.topic\n \n \n {{ \'tb.rulenode.topic-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Dn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.ackValues=["all","-1","0","1"],this.ToByteStandartCharsetTypesValues=At,this.ToByteStandartCharsetTypeTranslationMap=Mt}configForm(){return this.kafkaConfigForm}onConfigurationSet(e){this.kafkaConfigForm=this.fb.group({topicPattern:[e?e.topicPattern:null,[D.required]],keyPattern:[e?e.keyPattern:null],bootstrapServers:[e?e.bootstrapServers:null,[D.required]],retries:[e?e.retries:null,[D.min(0)]],batchSize:[e?e.batchSize:null,[D.min(0)]],linger:[e?e.linger:null,[D.min(0)]],bufferMemory:[e?e.bufferMemory:null,[D.min(0)]],acks:[e?e.acks:null,[D.required]],keySerializer:[e?e.keySerializer:null,[D.required]],valueSerializer:[e?e.valueSerializer:null,[D.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([D.required]):this.kafkaConfigForm.get("kafkaHeadersCharset").setValidators([]),this.kafkaConfigForm.get("kafkaHeadersCharset").updateValueAndValidity({emitEvent:e})}}e("KafkaConfigComponent",Dn),Dn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Dn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Dn,selector:"tb-external-node-kafka-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Dn,decorators:[{type:n,args:[{selector:"tb-external-node-kafka-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.key-pattern\n \n tb.rulenode.general-pattern-hint\n \n
tb.rulenode.key-pattern-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Vn 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,[D.required]],host:[e?e.host:null,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.max(65535)]],connectTimeoutSec:[e?e.connectTimeoutSec:null,[D.required,D.min(1),D.max(200)]],clientId:[e?e.clientId:null,[]],appendClientIdSuffix:[{value:!!e&&e.appendClientIdSuffix,disabled:!(e&&te(e.clientId))},[]],cleanSession:[!!e&&e.cleanSession,[]],retainedMessage:[!!e&&e.retainedMessage,[]],ssl:[!!e&&e.ssl,[]],credentials:[e?e.credentials:null,[]]})}updateValidators(e){te(this.mqttConfigForm.get("clientId").value)?this.mqttConfigForm.get("appendClientIdSuffix").enable({emitEvent:!1}):this.mqttConfigForm.get("appendClientIdSuffix").disable({emitEvent:!1}),this.mqttConfigForm.get("appendClientIdSuffix").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["clientId"]}}e("MqttConfigComponent",Vn),Vn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Vn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Vn,selector:"tb-external-node-mqtt-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"],dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Vn,decorators:[{type:n,args:[{selector:"tb-external-node-mqtt-config",template:'
\n \n tb.rulenode.topic-pattern\n \n \n {{ \'tb.rulenode.topic-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 {{\'tb.rulenode.client-id-hint\' | translate}}\n \n \n {{ \'tb.rulenode.append-client-id-suffix\' | translate }}\n \n
{{ "tb.rulenode.client-id-suffix-hint" | translate }}
\n \n {{ \'tb.rulenode.clean-session\' | translate }}\n \n \n {{ "tb.rulenode.retained-message" | translate }}\n \n \n {{ \'tb.rulenode.enable-ssl\' | translate }}\n \n \n
\n',styles:[":host .tb-mqtt-credentials-panel-group{margin:0 6px}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Pn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.notificationType=q,this.entityType=x}configForm(){return this.notificationConfigForm}onConfigurationSet(e){this.notificationConfigForm=this.fb.group({templateId:[e?e.templateId:null,[D.required]],targets:[e?e.targets:[],[D.required]]})}}e("NotificationConfigComponent",Pn),Pn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Pn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Pn,selector:"tb-external-node-notification-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n
\n',dependencies:[{kind:"component",type:Ke.EntityListComponent,selector:"tb-entity-list",inputs:["entityType","subType","labelText","placeholderText","requiredText","required","disabled","subscriptSizing","hint"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Ue.TemplateAutocompleteComponent,selector:"tb-template-autocomplete",inputs:["required","allowCreate","allowEdit","disabled","notificationTypes"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Pn,decorators:[{type:n,args:[{selector:"tb-external-node-notification-config",template:'
\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class wn 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,[D.required]],topicName:[e?e.topicName:null,[D.required]],serviceAccountKey:[e?e.serviceAccountKey:null,[D.required]],serviceAccountKeyFileName:[e?e.serviceAccountKeyFileName:null,[D.required]],messageAttributes:[e?e.messageAttributes:null,[]]})}}e("PubSubConfigComponent",wn),wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:wn,selector:"tb-external-node-pub-sub-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Pe.FileInputComponent,selector:"tb-file-input",inputs:["label","hint","accept","noFileText","inputId","allowedExtensions","dropLabel","contentConvertFunction","required","requiredAsError","disabled","existingFileName","readAsBinary","workFromFileObj","multipleFile"],outputs:["fileNameChanged"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:wn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Rn 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,[D.required]],port:[e?e.port:null,[D.required,D.min(1),D.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,[D.min(0)]],handshakeTimeout:[e?e.handshakeTimeout:null,[D.min(0)]],clientProperties:[e?e.clientProperties:null,[]]})}}e("RabbitMqConfigComponent",Rn),Rn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Rn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Rn,selector:"tb-external-node-rabbit-mq-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Rn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class On extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.proxySchemes=["http","https"],this.httpRequestTypes=Object.keys(qt)}configForm(){return this.restApiCallConfigForm}onConfigurationSet(e){this.restApiCallConfigForm=this.fb.group({restEndpointUrlPattern:[e?e.restEndpointUrlPattern:null,[D.required]],requestMethod:[e?e.requestMethod:null,[D.required]],useSimpleClientHttpFactory:[!!e&&e.useSimpleClientHttpFactory,[]],trimDoubleQuotes:[!!e&&e.trimDoubleQuotes,[]],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,[D.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,n=this.restApiCallConfigForm.get("useRedisQueueForMsgPersistence").value,r=this.restApiCallConfigForm.get("enableProxy").value,o=this.restApiCallConfigForm.get("useSystemProxyProperties").value;r&&!o?(this.restApiCallConfigForm.get("proxyHost").setValidators(r?[D.required]:[]),this.restApiCallConfigForm.get("proxyPort").setValidators(r?[D.required,D.min(1),D.max(65535)]:[])):(this.restApiCallConfigForm.get("proxyHost").setValidators([]),this.restApiCallConfigForm.get("proxyPort").setValidators([]),t?this.restApiCallConfigForm.get("readTimeoutMs").setValidators([]):this.restApiCallConfigForm.get("readTimeoutMs").setValidators([D.min(0)])),n?this.restApiCallConfigForm.get("maxQueueSize").setValidators([D.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})}}e("RestApiCallConfigComponent",On),On.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),On.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:On,selector:"tb-external-node-rest-api-call-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.endpoint-url-pattern\n \n \n {{ \'tb.rulenode.endpoint-url-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:fn,selector:"tb-credentials-config",inputs:["required","disableCertPemCredentials","passwordFieldRequired"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:On,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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.trim-double-quotes\' | translate }}\n \n
tb.rulenode.trim-double-quotes-hint
\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Bn 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,n=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([D.required]),this.sendEmailConfigForm.get("smtpHost").setValidators([D.required]),this.sendEmailConfigForm.get("smtpPort").setValidators([D.required,D.min(1),D.max(65535)]),this.sendEmailConfigForm.get("timeout").setValidators([D.required,D.min(0)]),this.sendEmailConfigForm.get("proxyHost").setValidators(n?[D.required]:[]),this.sendEmailConfigForm.get("proxyPort").setValidators(n?[D.required,D.min(1),D.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})}}e("SendEmailConfigComponent",Bn),Bn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Bn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Bn,selector:"tb-external-node-send-email-config",usesInheritance:!0,ngImport:t,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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:_e.TbCheckboxComponent,selector:"tb-checkbox",inputs:["disabled","trueValue","falseValue"],outputs:["valueChange"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:we.TogglePasswordComponent,selector:"tb-toggle-password"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Bn,decorators:[{type:n,args:[{selector:"tb-external-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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Kn 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,[D.required]],smsMessageTemplate:[e?e.smsMessageTemplate:null,[D.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([D.required]),this.sendSmsConfigForm.get("smsProviderConfiguration").updateValueAndValidity({emitEvent:e})}}e("SendSmsConfigComponent",Kn),Kn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Kn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Kn,selector:"tb-external-node-send-sms-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:He.SmsProviderConfigurationComponent,selector:"tb-sms-provider-configuration",inputs:["required","disabled"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Kn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-sms-settings\' | translate }}\n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Un extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.slackChanelTypes=Object.keys(A),this.slackChanelTypesTranslateMap=M}configForm(){return this.slackConfigForm}onConfigurationSet(e){this.slackConfigForm=this.fb.group({botToken:[e?e.botToken:null],useSystemSettings:[!!e&&e.useSystemSettings],messageTemplate:[e?e.messageTemplate:null,[D.required]],conversationType:[e?e.conversationType:null,[D.required]],conversation:[e?e.conversation:null,[D.required]]})}validatorTriggers(){return["useSystemSettings"]}updateValidators(e){this.slackConfigForm.get("useSystemSettings").value?this.slackConfigForm.get("botToken").clearValidators():this.slackConfigForm.get("botToken").setValidators([D.required]),this.slackConfigForm.get("botToken").updateValueAndValidity({emitEvent:e})}}e("SlackConfigComponent",Un),Un.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Un.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Un,selector:"tb-external-node-slack-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:B.MatCheckbox,selector:"mat-checkbox",inputs:["disableRipple","color","tabIndex"],exportAs:["matCheckbox"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:je.SlackConversationAutocompleteComponent,selector:"tb-slack-conversation-autocomplete",inputs:["labelText","requiredText","required","disabled","slackChanelType","token"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Un,decorators:[{type:n,args:[{selector:"tb-external-node-slack-config",template:'
\n \n tb.rulenode.message-template\n \n \n {{ \'tb.rulenode.message-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n \n {{ \'tb.rulenode.use-system-slack-settings\' | translate }}\n \n \n tb.rulenode.slack-api-token\n \n \n {{ \'tb.rulenode.slack-api-token-required\' | translate }}\n \n \n \n \n \n {{ slackChanelTypesTranslateMap.get(slackChanelType) | translate }}\n \n \n \n \n
\n',styles:[":host .tb-title{display:block;padding-bottom:6px}:host ::ng-deep .mat-mdc-radio-group{display:flex;flex-direction:row;margin-bottom:22px;gap:12px}:host ::ng-deep .mat-mdc-radio-group .mat-mdc-radio-button{flex:1 1 100%;padding:4px;border:1px solid rgba(0,0,0,.12);border-radius:6px}@media screen and (max-width: 599px){:host ::ng-deep .mat-mdc-radio-group{flex-direction:column}}\n"]}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class _n 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,[D.required]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SnsConfigComponent",_n),_n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),_n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:_n,selector:"tb-external-node-sns-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:_n,decorators:[{type:n,args:[{selector:"tb-external-node-sns-config",template:'
\n \n tb.rulenode.topic-arn-pattern\n \n \n {{ \'tb.rulenode.topic-arn-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Hn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.sqsQueueType=kt,this.sqsQueueTypes=Object.keys(kt),this.sqsQueueTypeTranslationsMap=Lt}configForm(){return this.sqsConfigForm}onConfigurationSet(e){this.sqsConfigForm=this.fb.group({queueType:[e?e.queueType:null,[D.required]],queueUrlPattern:[e?e.queueUrlPattern:null,[D.required]],delaySeconds:[e?e.delaySeconds:null,[D.min(0),D.max(900)]],messageAttributes:[e?e.messageAttributes:null,[]],accessKeyId:[e?e.accessKeyId:null,[D.required]],secretAccessKey:[e?e.secretAccessKey:null,[D.required]],region:[e?e.region:null,[D.required]]})}}e("SqsConfigComponent",Hn),Hn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Hn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Hn,selector:"tb-external-node-sqs-config",usesInheritance:!0,ngImport:t,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 tb.rulenode.general-pattern-hint\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',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Hn,decorators:[{type:n,args:[{selector:"tb-external-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 tb.rulenode.general-pattern-hint\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'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class zn{}e("RulenodeCoreConfigExternalModule",zn),zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,deps:[],target:t.ɵɵFactoryTarget.NgModule}),zn.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:zn,declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}),zn.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,imports:[O,T,Me,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:zn,decorators:[{type:l,args:[{declarations:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un],imports:[O,T,Me,vn],exports:[_n,Hn,wn,Dn,Vn,Pn,Rn,On,Bn,En,Kn,Un]}]}]});class jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.searchText=""}configForm(){return this.alarmStatusConfigForm}prepareInputConfig(e){return{alarmStatusList:X(e?.alarmStatusList)?e.alarmStatusList:null}}onConfigurationSet(e){this.alarmStatusConfigForm=this.fb.group({alarmStatusList:[e.alarmStatusList,[D.required]]})}}e("CheckAlarmStatusComponent",jn),jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:jn,selector:"tb-filter-node-check-alarm-status-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:hn,selector:"tb-alarm-status-select"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:jn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-alarm-status-config",template:'
\n
\n
tb.rulenode.alarm-status
\n
\n tb.rulenode.alarm-required\n
\n
\n \n
\n\n\n\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Qn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.checkMessageConfigForm}prepareInputConfig(e){return{messageNames:X(e?.messageNames)?e.messageNames:null,metadataNames:X(e?.metadataNames)?e.metadataNames:null,checkAllKeys:!!X(e?.checkAllKeys)&&e.checkAllKeys}}atLeastOne(e,t=null){return n=>{t||(t=Object.keys(n.controls));return n?.controls&&t.some((t=>!e(n.controls[t])))?null:{atLeastOne:!0}}}onConfigurationSet(e){this.checkMessageConfigForm=this.fb.group({messageNames:[e.messageNames,[]],metadataNames:[e.metadataNames,[]],checkAllKeys:[e.checkAllKeys,[]]},{validators:this.atLeastOne(D.required,["messageNames","metadataNames"])})}get touchedValidationControl(){return["messageNames","metadataNames"].some((e=>this.checkMessageConfigForm.get(e).touched))}}e("CheckMessageConfigComponent",Qn),Qn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Qn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Qn,selector:"tb-filter-node-check-message-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:Re.StringItemsListComponent,selector:"tb-string-items-list",inputs:["required","disabled","label","placeholder","hint","requiredText","floatLabel","appearance","editable","subscriptSizing","predefinedValues"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Qn,decorators:[{type:n,args:[{selector:"tb-filter-node-check-message-config",template:'
\n
\n
tb.rulenode.fields-to-check
\n
\n tb.rulenode.at-least-one-field-required\n
\n
\n \n help\n \n \n help\n \n
\n \n {{ \'tb.rulenode.check-all-keys\' | translate }}\n \n
\n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class $n extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.entitySearchDirection=Object.values(g),this.entitySearchDirectionTranslationsMap=y}configForm(){return this.checkRelationConfigForm}prepareInputConfig(e){return{checkForSingleEntity:!!X(e?.checkForSingleEntity)&&e.checkForSingleEntity,direction:X(e?.direction)?e.direction:null,entityType:X(e?.entityType)?e.entityType:null,entityId:X(e?.entityId)?e.entityId:null,relationType:X(e?.relationType)?e.relationType:null}}onConfigurationSet(e){this.checkRelationConfigForm=this.fb.group({checkForSingleEntity:[e.checkForSingleEntity,[]],direction:[e.direction,[]],entityType:[e.entityType,e&&e.checkForSingleEntity?[D.required]:[]],entityId:[e.entityId,e&&e.checkForSingleEntity?[D.required]:[]],relationType:[e.relationType,[D.required]]})}validatorTriggers(){return["checkForSingleEntity"]}updateValidators(e){const t=this.checkRelationConfigForm.get("checkForSingleEntity").value;this.checkRelationConfigForm.get("entityType").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.checkRelationConfigForm.get("entityId").setValidators(t?[D.required]:[]),this.checkRelationConfigForm.get("entityId").updateValueAndValidity({emitEvent:e})}}e("CheckRelationConfigComponent",$n),$n.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),$n.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:$n,selector:"tb-filter-node-check-relation-config",usesInheritance:!0,ngImport:t,template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"component",type:De.RelationTypeAutocompleteComponent,selector:"tb-relation-type-autocomplete",inputs:["showLabel","additionalClasses","appearance","required","disabled","subscriptSizing"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:$n,decorators:[{type:n,args:[{selector:"tb-filter-node-check-relation-config",template:'
\n
tb.rulenode.relation-search-parameters
\n
\n \n {{ \'relation.direction\' | translate }}\n \n \n {{ entitySearchDirectionTranslationsMap.get(direction) | translate }}\n \n \n \n \n \n
\n \n {{ \'tb.rulenode.check-relation-to-specific-entity\' | translate }}\n \n
\n
\n \n \n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Jn extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.perimeterType=lt,this.perimeterTypes=Object.values(lt),this.perimeterTypeTranslationMap=st,this.rangeUnits=Object.values(pt),this.rangeUnitTranslationMap=dt,this.defaultPaddingEnable=!0}configForm(){return this.geoFilterConfigForm}prepareInputConfig(e){return{latitudeKeyName:X(e?.latitudeKeyName)?e.latitudeKeyName:null,longitudeKeyName:X(e?.longitudeKeyName)?e.longitudeKeyName:null,perimeterType:X(e?.perimeterType)?e.perimeterType:null,fetchPerimeterInfoFromMessageMetadata:!!X(e?.fetchPerimeterInfoFromMessageMetadata)&&e.fetchPerimeterInfoFromMessageMetadata,perimeterKeyName:X(e?.perimeterKeyName)?e.perimeterKeyName:null,centerLatitude:X(e?.centerLatitude)?e.centerLatitude:null,centerLongitude:X(e?.centerLongitude)?e.centerLongitude:null,range:X(e?.range)?e.range:null,rangeUnit:X(e?.rangeUnit)?e.rangeUnit:null,polygonsDefinition:X(e?.polygonsDefinition)?e.polygonsDefinition:null}}onConfigurationSet(e){this.geoFilterConfigForm=this.fb.group({latitudeKeyName:[e.latitudeKeyName,[D.required]],longitudeKeyName:[e.longitudeKeyName,[D.required]],perimeterType:[e.perimeterType,[D.required]],fetchPerimeterInfoFromMessageMetadata:[e.fetchPerimeterInfoFromMessageMetadata,[]],perimeterKeyName:[e.perimeterKeyName,[]],centerLatitude:[e.centerLatitude,[]],centerLongitude:[e.centerLongitude,[]],range:[e.range,[]],rangeUnit:[e.rangeUnit,[]],polygonsDefinition:[e.polygonsDefinition,[]]})}validatorTriggers(){return["fetchPerimeterInfoFromMessageMetadata","perimeterType"]}updateValidators(e){const t=this.geoFilterConfigForm.get("fetchPerimeterInfoFromMessageMetadata").value,n=this.geoFilterConfigForm.get("perimeterType").value;t?this.geoFilterConfigForm.get("perimeterKeyName").setValidators([D.required]):this.geoFilterConfigForm.get("perimeterKeyName").setValidators([]),t||n!==lt.CIRCLE?(this.geoFilterConfigForm.get("centerLatitude").setValidators([]),this.geoFilterConfigForm.get("centerLongitude").setValidators([]),this.geoFilterConfigForm.get("range").setValidators([]),this.geoFilterConfigForm.get("rangeUnit").setValidators([]),this.defaultPaddingEnable=!0):(this.geoFilterConfigForm.get("centerLatitude").setValidators([D.required,D.min(-90),D.max(90)]),this.geoFilterConfigForm.get("centerLongitude").setValidators([D.required,D.min(-180),D.max(180)]),this.geoFilterConfigForm.get("range").setValidators([D.required,D.min(0)]),this.geoFilterConfigForm.get("rangeUnit").setValidators([D.required]),this.defaultPaddingEnable=!1),t||n!==lt.POLYGON?this.geoFilterConfigForm.get("polygonsDefinition").setValidators([]):this.geoFilterConfigForm.get("polygonsDefinition").setValidators([D.required]),this.geoFilterConfigForm.get("perimeterKeyName").updateValueAndValidity({emitEvent:e}),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})}}e("GpsGeoFilterConfigComponent",Jn),Jn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,deps:[{token:G.Store},{token:E.FormBuilder}],target:t.ɵɵFactoryTarget.Component}),Jn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Jn,selector:"tb-filter-node-gps-geofencing-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"component",type:Q.MatSlideToggle,selector:"mat-slide-toggle",inputs:["disabled","disableRipple","color","tabIndex"],exportAs:["matSlideToggle"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NumberValueAccessor,selector:"input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.MinValidator,selector:"input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]",inputs:["min"]},{kind:"directive",type:E.MaxValidator,selector:"input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]",inputs:["max"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:$.HintTooltipIconComponent,selector:"[tb-hint-tooltip-icon]",inputs:["tb-hint-tooltip-icon","tooltipPosition","hintIcon"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Jn,decorators:[{type:n,args:[{selector:"tb-filter-node-gps-geofencing-config",template:'
\n
\n
tb.rulenode.coordinate-field-names
\n
\n
\n \n {{ \'tb.rulenode.latitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.latitude-field-name-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.longitude-field-name\' | translate }}\n \n \n {{ \'tb.rulenode.longitude-field-name-required\' | translate }}\n \n \n
\n
tb.rulenode.coordinate-field-hint
\n
\n
\n
\n
tb.rulenode.geofence-configuration
\n
\n \n {{ \'tb.rulenode.perimeter-type\' | translate }}\n \n \n {{ perimeterTypeTranslationMap.get(type) | translate }}\n \n \n \n
\n \n {{ \'tb.rulenode.fetch-perimeter-info-from-metadata\' | translate }}\n \n
\n \n {{ \'tb.rulenode.perimeter-key-name\' | translate }}\n \n \n {{ \'tb.rulenode.perimeter-key-name-required\' | translate }}\n \n {{ \'tb.rulenode.perimeter-key-name-hint\' | translate }}\n \n
\n
\n \n {{ \'tb.rulenode.circle-center-latitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-latitude-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.circle-center-longitude\' | translate }}\n \n \n {{ \'tb.rulenode.circle-center-longitude-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.range\' | translate }}\n \n \n {{ \'tb.rulenode.range-required\' | translate }}\n \n \n \n {{ \'tb.rulenode.range-units\' | translate }}\n \n \n {{ rangeUnitTranslationMap.get(type) | translate }}\n \n \n \n {{ \'tb.rulenode.range-units-required\' | translate }}\n \n \n
\n
\n \n {{ \'tb.rulenode.polygon-definition\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-hint\' | translate }}\n \n {{ \'tb.rulenode.polygon-definition-required\' | translate }}\n \n \n
\n
\n
\n',styles:[":host .slide-toggle{margin-bottom:18px}\n",':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.FormBuilder}]}});class Yn extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.messageTypeConfigForm}prepareInputConfig(e){return{messageTypes:X(e?.messageTypes)?e.messageTypes:null}}onConfigurationSet(e){this.messageTypeConfigForm=this.fb.group({messageTypes:[e.messageTypes,[D.required]]})}}e("MessageTypeConfigComponent",Yn),Yn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Yn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Yn,selector:"tb-filter-node-message-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:cn,selector:"tb-message-types-config",inputs:["required","label","placeholder","disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Yn,decorators:[{type:n,args:[{selector:"tb-filter-node-message-type-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Wn 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}prepareInputConfig(e){return{originatorTypes:X(e?.originatorTypes)?e.originatorTypes:null}}onConfigurationSet(e){this.originatorTypeConfigForm=this.fb.group({originatorTypes:[e.originatorTypes,[D.required]]})}}e("OriginatorTypeConfigComponent",Wn),Wn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),Wn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Wn,selector:"tb-filter-node-originator-type-config",usesInheritance:!0,ngImport:t,template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n'],dependencies:[{kind:"component",type:$e.EntityTypeListComponent,selector:"tb-entity-type-list",inputs:["required","additionalClasses","appearance","label","floatLabel","disabled","subscriptSizing","allowedEntityTypes","emptyInputPlaceholder","filledInputPlaceholder","ignoreAuthorityFilter"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:U.MatSuffix,selector:"[matSuffix], [matIconSuffix], [matTextSuffix]",inputs:["matTextSuffix"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Wn,decorators:[{type:n,args:[{selector:"tb-filter-node-originator-type-config",template:'
\n \n help\n \n
\n',styles:[':host .margin-8{margin:8px}:host .tb-error{letter-spacing:.25px;color:var(--mdc-theme-error, #f44336)}:host .tb-required:after{content:"*"}\n']}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class Xn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-filter-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/filter_node_script_fn":"rulenode/tbel/filter_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"filter",this.translate.instant("tb.rulenode.filter"),"Filter",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("ScriptConfigComponent",Xn),Xn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Xn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Xn,selector:"tb-filter-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Xn,decorators:[{type:n,args:[{selector:"tb-filter-node-script-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class Zn extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-switch-function"}configForm(){return this.switchConfigForm}onConfigurationSet(e){this.switchConfigForm=this.fb.group({scriptLang:[e.scriptLang,[D.required]],jsScript:[e.jsScript,[]],tbelScript:[e.tbelScript,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.switchConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.switchConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.switchConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.switchConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.switchConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.switchConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.switchConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),{scriptLang:X(e?.scriptLang)?e.scriptLang:d.JS,jsScript:X(e?.jsScript)?e.jsScript:null,tbelScript:X(e?.tbelScript)?e.tbelScript:null}}testScript(e){const t=this.switchConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/switch_node_script_fn":"rulenode/tbel/switch_node_script_fn",o=this.switchConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"switch",this.translate.instant("tb.rulenode.switch"),"Switch",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.switchConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.switchConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("SwitchConfigComponent",Zn),Zn.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),Zn.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:Zn,selector:"tb-filter-node-switch-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n \n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:Zn,decorators:[{type:n,args:[{selector:"tb-filter-node-switch-config",template:'
\n \n \n \n \n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class er{}e("RuleNodeCoreConfigFilterModule",er),er.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,deps:[],target:t.ɵɵFactoryTarget.NgModule}),er.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:er,declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}),er.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:er,decorators:[{type:l,args:[{declarations:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn],imports:[O,T,vn],exports:[Qn,$n,Jn,Yn,Wn,Xn,Zn,jn]}]}]});class tr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.originatorSource=at,this.originatorSources=Object.keys(at),this.originatorSourceTranslationMap=it,this.allowedEntityTypes=[x.DEVICE,x.ASSET,x.ENTITY_VIEW,x.USER,x.EDGE]}configForm(){return this.changeOriginatorConfigForm}onConfigurationSet(e){this.changeOriginatorConfigForm=this.fb.group({originatorSource:[e?e.originatorSource:null,[D.required]],entityType:[e?e.entityType:null,[]],entityNamePattern:[e?e.entityNamePattern:null,[]],relationsQuery:[e?e.relationsQuery:null,[]]})}validatorTriggers(){return["originatorSource"]}updateValidators(e){const t=this.changeOriginatorConfigForm.get("originatorSource").value;t===at.RELATED?this.changeOriginatorConfigForm.get("relationsQuery").setValidators([D.required]):this.changeOriginatorConfigForm.get("relationsQuery").setValidators([]),t===at.ENTITY?(this.changeOriginatorConfigForm.get("entityType").setValidators([D.required]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([D.required,D.pattern(/.*\S.*/)])):(this.changeOriginatorConfigForm.get("entityType").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").patchValue(null,{emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").setValidators([]),this.changeOriginatorConfigForm.get("entityNamePattern").setValidators([])),this.changeOriginatorConfigForm.get("relationsQuery").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityType").updateValueAndValidity({emitEvent:e}),this.changeOriginatorConfigForm.get("entityNamePattern").updateValueAndValidity({emitEvent:e})}}e("ChangeOriginatorConfigComponent",tr),tr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),tr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:tr,selector:"tb-transformation-node-change-originator-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.originator-source\n \n \n {{ originatorSourceTranslationMap.get(source) | 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 tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:de.EntityTypeSelectComponent,selector:"tb-entity-type-select",inputs:["allowedEntityTypes","useAliasEntityTypes","filterAllowedEntityTypes","showLabel","required","disabled"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"component",type:xn,selector:"tb-relations-query-config-old",inputs:["disabled","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:tr,decorators:[{type:n,args:[{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 tb.rulenode.entity-name-pattern\n \n \n {{ \'tb.rulenode.entity-name-pattern-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n
\n \n \n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class nr extends s{constructor(e,t,n,o){super(e),this.store=e,this.fb=t,this.nodeScriptTestService=n,this.translate=o,this.tbelEnabled=Y(this.store).tbelEnabled,this.scriptLanguage=d,this.changeScript=new r,this.hasScript=!0,this.testScriptLabel="tb.rulenode.test-transformer-function"}configForm(){return this.scriptConfigForm}onConfigurationSet(e){this.scriptConfigForm=this.fb.group({scriptLang:[e?e.scriptLang:d.JS,[D.required]],jsScript:[e?e.jsScript:null,[D.required]],tbelScript:[e?e.tbelScript:null,[]]})}validatorTriggers(){return["scriptLang"]}updateValidators(e){let t=this.scriptConfigForm.get("scriptLang").value;t!==d.TBEL||this.tbelEnabled||(t=d.JS,this.scriptConfigForm.get("scriptLang").patchValue(t,{emitEvent:!1}),setTimeout((()=>{this.scriptConfigForm.updateValueAndValidity({emitEvent:!0})}))),this.scriptConfigForm.get("jsScript").setValidators(t===d.JS?[D.required]:[]),this.scriptConfigForm.get("jsScript").updateValueAndValidity({emitEvent:e}),this.scriptConfigForm.get("tbelScript").setValidators(t===d.TBEL?[D.required]:[]),this.scriptConfigForm.get("tbelScript").updateValueAndValidity({emitEvent:e})}prepareInputConfig(e){return e&&(e.scriptLang||(e.scriptLang=d.JS)),e}testScript(e){const t=this.scriptConfigForm.get("scriptLang").value,n=t===d.JS?"jsScript":"tbelScript",r=t===d.JS?"rulenode/transformation_node_script_fn":"rulenode/tbel/transformation_node_script_fn",o=this.scriptConfigForm.get(n).value;this.nodeScriptTestService.testNodeScript(o,"update",this.translate.instant("tb.rulenode.transformer"),"Transform",["msg","metadata","msgType"],this.ruleNodeId,r,t,e).subscribe((e=>{e&&(this.scriptConfigForm.get(n).setValue(e),this.changeScript.emit())}))}onValidate(){this.scriptConfigForm.get("scriptLang").value===d.JS&&this.jsFuncComponent.validateOnSubmit()}}e("TransformScriptConfigComponent",nr),nr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,deps:[{token:G.Store},{token:E.UntypedFormBuilder},{token:W.NodeScriptTestService},{token:H.TranslateService}],target:t.ɵɵFactoryTarget.Component}),nr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:nr,selector:"tb-transformation-node-script-config",viewQueries:[{propertyName:"jsFuncComponent",first:!0,predicate:["jsFuncComponent"],descendants:!0},{propertyName:"tbelFuncComponent",first:!0,predicate:["tbelFuncComponent"],descendants:!0}],usesInheritance:!0,ngImport:t,template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n',dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:ne.JsFuncComponent,selector:"tb-js-func",inputs:["functionTitle","functionName","functionArgs","validationArgs","resultType","disabled","fillHeight","minHeight","editorCompleter","globalVariables","disableUndefinedCheck","helpId","scriptLanguage","noValidate","required"]},{kind:"component",type:re.MatButton,selector:" button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:re.MatIconButton,selector:"button[mat-icon-button]",inputs:["disabled","disableRipple","color"],exportAs:["matButton"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:ae.MatTooltip,selector:"[matTooltip]",exportAs:["matTooltip"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:ie.TbScriptLangComponent,selector:"tb-script-lang",inputs:["disabled"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:nr,decorators:[{type:n,args:[{selector:"tb-transformation-node-script-config",template:'
\n \n \n \n \n \n \n \n
\n \n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder},{type:W.NodeScriptTestService},{type:H.TranslateService}]},propDecorators:{jsFuncComponent:[{type:o,args:["jsFuncComponent",{static:!1}]}],tbelFuncComponent:[{type:o,args:["tbelFuncComponent",{static:!1}]}]}});class rr 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,[D.required]],toTemplate:[e?e.toTemplate:null,[D.required]],ccTemplate:[e?e.ccTemplate:null,[]],bccTemplate:[e?e.bccTemplate:null,[]],subjectTemplate:[e?e.subjectTemplate:null,[D.required]],mailBodyType:[e?e.mailBodyType:null],isHtmlTemplate:[e?e.isHtmlTemplate:null,[D.required]],bodyTemplate:[e?e.bodyTemplate:null,[D.required]]})}updateValidators(e){"dynamic"===this.toEmailConfigForm.get("mailBodyType").value?this.toEmailConfigForm.get("isHtmlTemplate").enable({emitEvent:!1}):this.toEmailConfigForm.get("isHtmlTemplate").disable({emitEvent:!1}),this.toEmailConfigForm.get("isHtmlTemplate").updateValueAndValidity({emitEvent:e})}validatorTriggers(){return["mailBodyType"]}}e("ToEmailConfigComponent",rr),rr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),rr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:rr,selector:"tb-transformation-node-to-email-config",usesInheritance:!0,ngImport:t,template:'
\n \n tb.rulenode.from-template\n \n \n {{ \'tb.rulenode.from-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"component",type:z.MatSelect,selector:"mat-select",inputs:["disabled","disableRipple","tabIndex","hideSingleSelectionIndicator"],exportAs:["matSelect"]},{kind:"component",type:j.MatOption,selector:"mat-option",exportAs:["matOption"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:pe.SafePipe,name:"safe"},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:rr,decorators:[{type:n,args:[{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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\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 tb.rulenode.general-pattern-hint\n \n \n tb.rulenode.body-template\n \n \n {{ \'tb.rulenode.body-template-required\' | translate }}\n \n tb.rulenode.general-pattern-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class or extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.copyKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.copyKeysConfigForm}removeKey(e){const t=this.copyKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.copyKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.copyKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.copyKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("CopyKeysConfigComponent",or),or.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),or.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:or,selector:"tb-transformation-node-copy-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:or,decorators:[{type:n,args:[{selector:"tb-transformation-node-copy-keys-config",template:'
\n
{{\'tb.rulenode.copy-from\' | translate}}
\n \n \n {{\'tb.rulenode.data-to-metadata\' | translate}}\n \n \n {{\'tb.rulenode.metadata-to-data\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ar extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.renameKeysConfigForm}onConfigurationSet(e){this.renameKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],renameKeysMapping:[e?e.renameKeysMapping:null,[D.required]]})}}e("RenameKeysConfigComponent",ar),ar.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ar.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ar,selector:"tb-transformation-node-rename-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n',dependencies:[{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"component",type:Xt,selector:"tb-kv-map-config-old",inputs:["disabled","uniqueKeyValuePairValidator","requiredText","keyText","keyRequiredText","valText","valRequiredText","hintText","required"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ar,decorators:[{type:n,args:[{selector:"tb-transformation-node-rename-keys-config",template:'
\n
{{ \'tb.rulenode.rename-keys-in\' | translate }}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ir extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.jsonPathConfigForm}onConfigurationSet(e){this.jsonPathConfigForm=this.fb.group({jsonPath:[e?e.jsonPath:null,[D.required]]})}}e("NodeJsonPathConfigComponent",ir),ir.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ir.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ir,selector:"tb-transformation-node-json-path-config",usesInheritance:!0,ngImport:t,template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n",dependencies:[{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatLabel,selector:"mat-label"},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.DefaultValueAccessor,selector:"input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]"},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ir,decorators:[{type:n,args:[{selector:"tb-transformation-node-json-path-config",template:"
\n \n {{ 'tb.rulenode.json-path-expression' | translate }}\n \n {{ 'tb.rulenode.json-path-expression-hint' | translate }}\n {{ 'tb.rulenode.json-path-expression-required' | translate }}\n \n
\n\n"}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class lr extends s{constructor(e,t){super(e),this.store=e,this.fb=t,this.separatorKeysCodes=[le,se,me]}onConfigurationSet(e){this.deleteKeysConfigForm=this.fb.group({fromMetadata:[e?e.fromMetadata:null,[D.required]],keys:[e?e.keys:null,[D.required]]})}configForm(){return this.deleteKeysConfigForm}removeKey(e){const t=this.deleteKeysConfigForm.get("keys").value,n=t.indexOf(e);n>=0&&(t.splice(n,1),this.deleteKeysConfigForm.get("keys").patchValue(t,{emitEvent:!0}))}addKey(e){const t=e.input;let n=e.value;if((n||"").trim()){n=n.trim();let e=this.deleteKeysConfigForm.get("keys").value;e&&-1!==e.indexOf(n)||(e||(e=[]),e.push(n),this.deleteKeysConfigForm.get("keys").patchValue(e,{emitEvent:!0}))}t&&(t.value="")}}e("DeleteKeysConfigComponent",lr),lr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),lr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:lr,selector:"tb-transformation-node-delete-keys-config",usesInheritance:!0,ngImport:t,template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n',dependencies:[{kind:"directive",type:R.NgForOf,selector:"[ngFor][ngForOf]",inputs:["ngForOf","ngForTrackBy","ngForTemplate"]},{kind:"directive",type:R.NgIf,selector:"[ngIf]",inputs:["ngIf","ngIfThen","ngIfElse"]},{kind:"component",type:oe.MatIcon,selector:"mat-icon",inputs:["color","inline","svgIcon","fontSet","fontIcon"],exportAs:["matIcon"]},{kind:"directive",type:K.MatInput,selector:"input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]",inputs:["disabled","id","placeholder","name","required","type","errorStateMatcher","aria-describedby","value","readonly"],exportAs:["matInput"]},{kind:"component",type:U.MatFormField,selector:"mat-form-field",inputs:["hideRequiredMarker","color","floatLabel","appearance","subscriptSizing","hintLabel"],exportAs:["matFormField"]},{kind:"directive",type:U.MatHint,selector:"mat-hint",inputs:["align","id"]},{kind:"directive",type:U.MatError,selector:"mat-error, [matError]",inputs:["id"]},{kind:"directive",type:ze.MatRadioGroup,selector:"mat-radio-group",exportAs:["matRadioGroup"]},{kind:"component",type:ze.MatRadioButton,selector:"mat-radio-button",inputs:["disableRipple","tabIndex"],exportAs:["matRadioButton"]},{kind:"component",type:ue.MatChipGrid,selector:"mat-chip-grid",inputs:["tabIndex","disabled","placeholder","required","value","errorStateMatcher"],outputs:["change","valueChange"]},{kind:"directive",type:ue.MatChipInput,selector:"input[matChipInputFor]",inputs:["matChipInputFor","matChipInputAddOnBlur","matChipInputSeparatorKeyCodes","placeholder","id","disabled"],outputs:["matChipInputTokenEnd"],exportAs:["matChipInput","matChipInputFor"]},{kind:"directive",type:ue.MatChipRemove,selector:"[matChipRemove]"},{kind:"component",type:ue.MatChipRow,selector:"mat-chip-row, [mat-chip-row], mat-basic-chip-row, [mat-basic-chip-row]",inputs:["color","disabled","disableRipple","tabIndex","editable"],outputs:["edited"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:_.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"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]},{kind:"directive",type:H.TranslateDirective,selector:"[translate],[ngx-translate]",inputs:["translate","translateParams"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:lr,decorators:[{type:n,args:[{selector:"tb-transformation-node-delete-keys-config",template:'
\n
{{\'tb.rulenode.delete-from\' | translate}}
\n \n \n {{\'tb.rulenode.data\' | translate}}\n \n \n {{\'tb.rulenode.metadata\' | translate}}\n \n \n \n \n \n {{key}}\n close\n \n \n \n {{ \'tb.rulenode.keys-required\' | translate }}\n tb.rulenode.use-regular-expression-delete-hint\n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class sr{}e("RulenodeCoreConfigTransformModule",sr),sr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),sr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:sr,declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}),sr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:sr,decorators:[{type:l,args:[{declarations:[tr,nr,rr,or,ar,ir,lr],imports:[O,T,vn],exports:[tr,nr,rr,or,ar,ir,lr]}]}]});class mr 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,[D.required]]})}}e("RuleChainInputComponent",mr),mr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),mr.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:mr,selector:"tb-flow-node-rule-chain-input-config",usesInheritance:!0,ngImport:t,template:'
\n \n \n
\n',dependencies:[{kind:"component",type:Qe.EntityAutocompleteComponent,selector:"tb-entity-autocomplete",inputs:["entityType","entitySubtype","excludeEntityIds","labelText","requiredText","useFullEntityId","appearance","required","disabled"],outputs:["entityChanged"]},{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatus,selector:"[formControlName],[ngModel],[formControl]"},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.RequiredValidator,selector:":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]",inputs:["required"]},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"directive",type:E.FormControlName,selector:"[formControlName]",inputs:["formControlName","disabled","ngModel"],outputs:["ngModelChange"]}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:mr,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-input-config",template:'
\n \n \n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class ur extends s{constructor(e,t){super(e),this.store=e,this.fb=t}configForm(){return this.ruleChainOutputConfigForm}onConfigurationSet(e){this.ruleChainOutputConfigForm=this.fb.group({})}}e("RuleChainOutputComponent",ur),ur.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,deps:[{token:G.Store},{token:E.UntypedFormBuilder}],target:t.ɵɵFactoryTarget.Component}),ur.ɵcmp=t.ɵɵngDeclareComponent({minVersion:"14.0.0",version:"15.2.9",type:ur,selector:"tb-flow-node-rule-chain-output-config",usesInheritance:!0,ngImport:t,template:'
\n
\n
\n',dependencies:[{kind:"directive",type:_.DefaultLayoutDirective,selector:" [fxLayout], [fxLayout.xs], [fxLayout.sm], [fxLayout.md], [fxLayout.lg], [fxLayout.xl], [fxLayout.lt-sm], [fxLayout.lt-md], [fxLayout.lt-lg], [fxLayout.lt-xl], [fxLayout.gt-xs], [fxLayout.gt-sm], [fxLayout.gt-md], [fxLayout.gt-lg]",inputs:["fxLayout","fxLayout.xs","fxLayout.sm","fxLayout.md","fxLayout.lg","fxLayout.xl","fxLayout.lt-sm","fxLayout.lt-md","fxLayout.lt-lg","fxLayout.lt-xl","fxLayout.gt-xs","fxLayout.gt-sm","fxLayout.gt-md","fxLayout.gt-lg"]},{kind:"directive",type:E.NgControlStatusGroup,selector:"[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]"},{kind:"directive",type:E.FormGroupDirective,selector:"[formGroup]",inputs:["formGroup"],outputs:["ngSubmit"],exportAs:["ngForm"]},{kind:"pipe",type:H.TranslatePipe,name:"translate"}]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:ur,decorators:[{type:n,args:[{selector:"tb-flow-node-rule-chain-output-config",template:'
\n
\n
\n'}]}],ctorParameters:function(){return[{type:G.Store},{type:E.UntypedFormBuilder}]}});class pr{}e("RuleNodeCoreConfigFlowModule",pr),pr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,deps:[],target:t.ɵɵFactoryTarget.NgModule}),pr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:pr,declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}),pr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,imports:[O,T,vn]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:pr,decorators:[{type:l,args:[{declarations:[mr,ur],imports:[O,T,vn],exports:[mr,ur]}]}]});class dr{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","output-message-type":"Output message type","output-message-type-required":"Output message type is required","output-message-type-max-length":"Output message type should be less than 256","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.","interval-start":"Interval start","interval-end":"Interval end","time-unit":"Time unit","fetch-mode":"Fetch mode","order-by-timestamp":"Order by timestamp",limit:"Limit","limit-hint":"Min limit value is 2, max - 1000. If you want to fetch a single entry, select fetch mode 'First' or 'Last'.","limit-required":"Limit is required.","limit-range":"Limit should be in a range from 2 to 1000.","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Allowing range from 1 to 2147483647.","start-interval-value-required":"Interval start is required.","end-interval-value-required":"Interval end is required.",filter:"Filter",switch:"Switch","math-templatization-tooltip":"This field support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","add-message-type":"Add message type","select-message-types-required":"At least one message type should be selected.","select-message-types":"Select message types","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","attributes-keys":"Attributes keys","attributes-keys-required":"Attributes keys are required","notify-device":"Notify device","send-attributes-updated-notification":"Send attributes updated notification","send-attributes-updated-notification-hint":"Send notification about updated attributes as a separate message to the rule engine queue.","send-attributes-deleted-notification":"Send attributes deleted notification","send-attributes-deleted-notification-hint":"Send notification about deleted attributes as a separate message to the rule engine queue.","update-attributes-only-on-value-change":"Save attributes only if the value changes","update-attributes-only-on-value-change-hint":"Updates the attributes on every incoming message disregarding if their value has changed. Increases API usage and reduces performance.","update-attributes-only-on-value-change-hint-enabled":"Updates the attributes only if their value has changed. If the value is not changed, no update to the attribute timestamp nor attribute change notification will be sent.","fetch-credentials-to-metadata":"Fetch credentials to metadata","notify-device-hint":"If the message arrives from the device, we will push it back to the device by default.","notify-device-delete-hint":"Send notification about deleted attributes to device.","latest-timeseries":"Latest time-series data keys","timeseries-keys":"Timeseries keys","timeseries-keys-required":"At least one timeseries key should be selected.","add-timeseries-key":"Add timeseries key","add-message-field":"Add message field","relation-search-parameters":"Relation search parameters","add-metadata-field":"Add metadata field","data-keys":"Message field names","copy-from":"Copy from","data-to-metadata":"Data to metadata","metadata-to-data":"Metadata to data","use-regular-expression-hint":"Use regular expression to copy keys by pattern",interval:"Interval","interval-required":"Interval is required","interval-hint":"Deduplication interval in seconds.","interval-min-error":"Min allowed value is 1","max-pending-msgs":"Max pending messages","max-pending-msgs-hint":"Maximum number of messages that are stored in memory for each unique deduplication id.","max-pending-msgs-required":"Max pending messages is required","max-pending-msgs-max-error":"Max allowed value is 1000","max-pending-msgs-min-error":"Min allowed value is 1","max-retries":"Max retries","max-retries-required":"Max retries is required","max-retries-hint":"Maximum number of retries to push the deduplicated messages into the queue. 10 seconds delay is used between retries","max-retries-max-error":"Max allowed value is 100","max-retries-min-error":"Min allowed value is 0",strategy:"Strategy","strategy-required":"Strategy is required","strategy-all-hint":"Return all messages that arrived during deduplication period as a single JSON array message. Where each element represents object with msg and metadata inner properties.","strategy-first-hint":"Return first message that arrived during deduplication period.","strategy-last-hint":"Return last message that arrived during deduplication period.",first:"First",last:"Last",all:"All","output-msg-type-hint":"The message type of the deduplication result.","queue-name-hint":"The queue name where the deduplication result will be published.",keys:"Keys","keys-required":"Keys are required","rename-keys-in":"Rename keys in",data:"Data",message:"Message",metadata:"Metadata","key-name":"Key name","key-name-required":"Key name is required","new-key-name":"New key name","new-key-name-required":"New key name is required","metadata-keys":"Metadata field names","json-path-expression":"JSON path expression","json-path-expression-required":"JSON path expression is required","json-path-expression-hint":"JSONPath specifies a path to an element or a set of elements in a JSON structure. '$' represents the root object or array.","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","max-relation-level-error":"Value should be greater than 0 or unspecified.","relation-type":"Relation type","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","add-telemetry-key":"Add telemetry key","delete-from":"Delete from","use-regular-expression-delete-hint":"Use regular expression to delete keys by pattern","fetch-into":"Fetch into","attr-mapping":"Attributes mapping:","source-attribute":"Source attribute key","source-attribute-required":"Source attribute key is required.","source-telemetry":"Source telemetry key","source-telemetry-required":"Source telemetry key is required.","target-key":"Target key","target-key-required":"Target key is required.","attr-mapping-required":"At least one mapping entry should be specified.","fields-mapping":"Fields mapping*","fields-mapping-required":"At least one field mapping should be specified.","at-least-one-field-required":"At least one input field must have a value(s) provided.","originator-fields-sv-map-hint":"Target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","sv-map-hint":"Only target key fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","originator-entity":"Entity","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","select-entity-types":"Select entity types","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required","alarm-severity-pattern":"Alarm severity pattern","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 alarm to related entities","propagate-to-owner":"Propagate alarm to entity owner (Customer or Tenant)","propagate-to-tenant":"Propagate alarm to Tenant",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","trim-double-quotes":"Message without quotes","trim-double-quotes-hint":"If selected, request body message payload will be sent without double quotes, i.e. msg = message 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","key-pattern":"Key pattern","key-pattern-hint":"Optional. If a valid partition number is specified, it will be used when sending the record. If no partition is specified, the key will be used instead. If neither is specified, a partition will be assigned in a round-robin fashion.","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":'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 node is 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. To avoid such failures enable "Add Service ID as suffix to Client ID" option below.',"append-client-id-suffix":"Add Service ID as suffix to Client ID","client-id-suffix-hint":'Optional. Applied when "Client ID" specified explicitly. If selected then Service ID will be added to Client ID as a suffix. Helps to avoid failures when platform is running in a micro-services mode.',"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-dynamic-interval":"Use dynamic interval","metadata-dynamic-interval-hint":"Interval start and end input fields support templatization. Note that the substituted template value should be set in milliseconds. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","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","overwrite-alarm-details":"Overwrite alarm details","use-alarm-severity-pattern":"Use alarm severity pattern","check-all-keys":"Check that all specified fields 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-to-specific-entity-tooltip":"If enabled, checks the presence of relation with a specific entity otherwise, checks the presence of relation with any entity. In both cases, relation lookup is based on configured direction and type.","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":"Interval start","end-interval":"Interval end","start-interval-required":"Interval start is required.","end-interval-required":"Interval end 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":'Press "Enter" to complete field input.',"select-details":"Select details","entity-details-id":"Id","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","fields-to-check":"Fields to check","add-detail":"Add detail","check-all-keys-tooltip":"If enabled, checks the presence of all fields listed in the message and metadata field names within the incoming message and its metadata.","fields-to-check-hint":'Press "Enter" to complete field name input. Multiple field names supported.',"entity-details-list-empty":"At least one detail should be selected.","alarm-status":"Alarm status","alarm-required":"At least one alarm status should be 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":"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-field-name":"Latitude field name","longitude-field-name":"Longitude field name","latitude-field-name-required":"Latitude field name is required.","longitude-field-name-required":"Longitude field name is required.","fetch-perimeter-info-from-metadata":"Fetch perimeter information from metadata","fetch-perimeter-info-from-metadata-tooltip":"If perimeter type is set to 'Polygon' the value of metadata field '{{perimeterKeyName}}' will be set as perimeter definition without additional parsing of the value. Otherwise, if perimeter type is set to 'Circle' the value of '{{perimeterKeyName}}' metadata field will be parsed to extract 'latitude', 'longitude', 'radius', 'radiusUnit' fields that uses for circle perimeter definition.","perimeter-key-name":"Perimeter key name","perimeter-key-name-hint":"Metadata field name that includes perimeter information.","perimeter-key-name-required":"Perimeter key name is required.","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-units-required":"Range units is required.",range:"Range","range-required":"Range is required.","polygon-definition":"Polygon definition","polygon-definition-required":"Polygon definition is required.","polygon-definition-hint":"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 timestamp for the latest telemetry values","get-latest-value-with-ts-hint":'If selected, the latest telemetry values will also include timestamp, e.g: "temp": "{"ts":1574329385897, "value":42}"',"use-redis-queue":"Use redis queue for message persistence","ignore-null-strings":"Ignore null strings","ignore-null-strings-hint":"If selected rule node will ignore entity fields with empty value.","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.","number-of-digits-after-floating-point":"Number of digits after floating point","number-of-digits-after-floating-point-range":"Number of digits after floating point should be in a range from 0 to 15.","failure-if-delta-negative":"Tell Failure if delta is negative","failure-if-delta-negative-tooltip":"Rule node forces failure of message processing if delta value is negative.","use-caching":"Use caching","use-caching-tooltip":'Rule node will cache the value of "{{inputValueKey}}" that arrives from the incoming message to improve performance. Note that the cache will not be updated if you modify the "{{inputValueKey}}" value elsewhere.',"add-time-difference-between-readings":'Add the time difference between "{{inputValueKey}}" readings',"add-time-difference-between-readings-tooltip":'If enabled, the rule node will add the "{{periodValueKey}}" to the outbound message.',"period-value-key":"Period value key","period-value-key-required":"Period value key is required.","general-pattern-hint":"Use ${metadataKey} for value from metadata, $[messageKey] for value from message body.","alarm-severity-pattern-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","use-server-ts":"Use server ts","use-server-ts-hint":"Enable this setting 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).","kv-map-pattern-hint":"All input fields support templatization. Use $[messageKey] to extract value from the message and ${metadataKey} to extract value from the metadata.","shared-scope":"Shared scope","server-scope":"Server scope","client-scope":"Client scope","attribute-type":"Attribute","constant-type":"Constant","time-series-type":"Time-series","message-body-type":"Message","message-metadata-type":"Metadata","argument-tile":"Arguments","no-arguments-prompt":"No arguments configured","result-title":"Result","functions-field-input":"Functions","no-option-found":"No option found","argument-source-field-input":"Source","argument-source-field-input-required":"Argument source is required.","argument-key-field-input":"Key","argument-key-field-input-required":"Argument key is required.","constant-value-field-input":"Constant value","constant-value-field-input-required":"Constant value is required.","attribute-scope-field-input":"Attribute scope","attribute-scope-field-input-required":"Attribute scope os required.","default-value-field-input":"Default value","type-field-input":"Type","type-field-input-required":"Type is required.","key-field-input":"Key","add-entity-type":"Add entity type","key-field-input-required":"Key is required.","number-floating-point-field-input":"Number of digits after floating point","number-floating-point-field-input-hint":"Use 0 to convert result to integer","add-to-message-field-input":"Add to message","add-to-metadata-field-input":"Add to metadata","custom-expression-field-input":"Mathematical Expression","custom-expression-field-input-required":"Mathematical expression is required","custom-expression-field-input-hint":"Specify a mathematical expression to evaluate. Default expression demonstrates how to transform Fahrenheit to Celsius","retained-message":"Retained","attributes-mapping":"Attributes mapping","latest-telemetry-mapping":"Latest telemetry mapping","add-mapped-attribute-to":"Add mapped attributes to","add-mapped-latest-telemetry-to":"Add mapped latest telemetry to","add-mapped-fields-to":"Add mapped fields to","add-selected-details-to":"Add selected details to","clear-selected-types":"Clear selected types","clear-selected-details":"Clear selected details","clear-selected-fields":"Clear selected fields","clear-selected-keys":"Clear selected keys","geofence-configuration":"Geofence configuration","coordinate-field-names":"Coordinate field names","coordinate-field-hint":"Rule node tries to retrieve the specified fields from the message. If they are not present, it will look them up in the metadata.","fetch-credentials-to":"Fetch credentials to","add-originator-attributes-to":"Add originator attributes to","originator-attributes":"Originator attributes","fetch-latest-telemetry-with-timestamp":"Fetch latest telemetry with timestamp","fetch-latest-telemetry-with-timestamp-tooltip":'If selected, latest telemetry values will be added to the outbound metadata with timestamp, e.g: "{{latestTsKeyName}}": "{"ts":1574329385897, "value":42}"',"tell-failure":"Tell failure if any of the attributes are missing","tell-failure-tooltip":'If at least one selected key doesn\'t exist the outbound message will report "Failure".',"created-time":"Created time","chip-help":"Press 'Enter' to complete {{inputName}} input. \nPress 'Backspace' to delete {{inputName}}. \nMultiple values supported.",detail:"detail","field-name":"field name","device-profile":"device profile","entity-type":"entity type","message-type":"message type","timeseries-key":"timeseries key",type:"Type","first-name":"First name","last-name":"Last name",label:"Label","originator-fields-mapping":"Originator fields mapping","add-mapped-originator-fields-to":"Add mapped originator fields to",fields:"Fields","skip-empty-fields":"Skip empty fields","skip-empty-fields-tooltip":"Fields with empty values will not be added to the output message/output metadata.","fetch-interval":"Fetch interval","fetch-strategy":"Fetch strategy","fetch-timeseries-from-to":"Fetch timeseries from {{startInterval}} {{startIntervalTimeUnit}} ago to {{endInterval}} {{endIntervalTimeUnit}} ago.","fetch-timeseries-from-to-invalid":'Fetch timeseries invalid ("Interval start" should be less than "Interval end").',"use-metadata-dynamic-interval-tooltip":"If selected, the rule node will use dynamic interval start and end based on the message and metadata patterns.","all-mode-hint":'If selected fetch mode "All" rule node will retrieve telemetry from the fetch interval with configurable query parameters.',"first-mode-hint":'If selected fetch mode "First" rule node will retrieve the closest telemetry to the fetch interval\'s start.',"last-mode-hint":'If selected fetch mode "Last" rule node will retrieve the closest telemetry to the fetch interval\'s end.',ascending:"Ascending",descending:"Descending",min:"Min",max:"Max",average:"Average",sum:"Sum",count:"Count",none:"None","last-level-relation-tooltip":"If selected, the rule node will search related entities only on the level set in the max relation level.","last-level-device-relation-tooltip":"If selected, the rule node will search related devices only on the level set in the max relation level.","data-to-fetch":"Data to fetch","mapping-of-customers-fields":"Mapping of customer's fields","map-fields-required":"All mapping fields are required.",attributes:"Attributes","related-device-attributes":"Related device attributes","add-selected-attributes-to":"Add selected attributes to","device-profiles":"Device profiles","mapping-of-tenant-fields":"Mapping of tenant's fields","add-attribute-key":"Add attribute key","message-template":"Message template","message-template-required":"Message template is required","use-system-slack-settings":"Use system slack settings","slack-api-token":"Slack API token","slack-api-token-required":"Slack API token is required"},"key-val":{key:"Key",value:"Value","see-examples":"See examples.","remove-entry":"Remove entry","remove-mapping-entry":"Remove mapping entry","add-mapping-entry":"Add mapping","add-entry":"Add entry","unique-key-value-pair-error":"'{{valText}}' must be different from the current '{{keyText}}'"},"mail-body-type":{"plain-text":"Plain Text",html:"HTML",dynamic:"Dynamic"}}},!0)}(e)}}e("RuleNodeCoreConfigModule",dr),dr.ɵfac=t.ɵɵngDeclareFactory({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,deps:[{token:H.TranslateService}],target:t.ɵɵFactoryTarget.NgModule}),dr.ɵmod=t.ɵɵngDeclareNgModule({minVersion:"14.0.0",version:"15.2.9",ngImport:t,type:dr,declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}),dr.ɵinj=t.ɵɵngDeclareInjector({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,imports:[O,T,Cn,er,Gn,zn,sr,pr]}),t.ɵɵngDeclareClassMetadata({minVersion:"12.0.0",version:"15.2.9",ngImport:t,type:dr,decorators:[{type:l,args:[{declarations:[Je],imports:[O,T],exports:[Cn,er,Gn,zn,sr,pr,Je]}]}],ctorParameters:function(){return[{type:H.TranslateService}]}})}}}));//# sourceMappingURL=rulenode-core-config.js.map From 995ea59f9a4028835d2d430e9df429a65febadcc Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 20 Sep 2023 17:44:42 +0300 Subject: [PATCH 098/267] Update UI help links path --- 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 306e9a798c..d1e5113449 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -167,7 +167,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.5.1}" + base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.6}" database: ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records From 8f1c13b3354715662f7190937aae35934b1aaf77 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 21 Sep 2023 17:03:04 +0300 Subject: [PATCH 099/267] added api rate limits tbel --- .../main/data/upgrade/3.6.0/schema_update.sql | 18 +++++++++++++++++ .../service/apiusage/BaseApiUsageState.java | 5 +++++ .../install/SqlDatabaseUpgradeService.java | 15 ++++++++++++++ .../service/mail/DefaultMailService.java | 4 ++++ .../server/controller/HomePageApiTest.java | 3 +++ .../server/common/data/ApiFeature.java | 1 + .../server/common/data/ApiUsageRecordKey.java | 4 ++++ .../server/common/data/ApiUsageState.java | 6 ++++++ .../server/common/data/UsageInfo.java | 2 ++ .../DefaultTenantProfileConfiguration.java | 3 +++ .../api/AbstractScriptInvokeService.java | 20 ++++++------------- .../api/js/AbstractJsInvokeService.java | 17 +++++++++++++++- .../api/tbel/DefaultTbelInvokeService.java | 17 +++++++++++++++- .../server/dao/model/ModelConstants.java | 1 + .../dao/model/sql/ApiUsageStateEntity.java | 5 +++++ .../dao/usage/BasicUsageInfoService.java | 3 +++ .../usagerecord/ApiUsageStateServiceImpl.java | 3 +++ .../main/resources/sql/schema-entities.sql | 1 + 18 files changed, 112 insertions(+), 16 deletions(-) create mode 100644 application/src/main/data/upgrade/3.6.0/schema_update.sql diff --git a/application/src/main/data/upgrade/3.6.0/schema_update.sql b/application/src/main/data/upgrade/3.6.0/schema_update.sql new file mode 100644 index 0000000000..81a0e5443f --- /dev/null +++ b/application/src/main/data/upgrade/3.6.0/schema_update.sql @@ -0,0 +1,18 @@ +-- +-- Copyright © 2016-2023 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. +-- + +ALTER TABLE api_usage_state ADD COLUMN IF NOT EXISTS tbel_exec varchar(32); +UPDATE api_usage_state SET tbel_exec = js_exec WHERE tbel_exec IS NULL; \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java b/application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java index 1215bef0bf..9ae25fe2ef 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/BaseApiUsageState.java @@ -145,6 +145,8 @@ public abstract class BaseApiUsageState { return apiUsageState.getDbStorageState(); case JS: return apiUsageState.getJsExecState(); + case TBEL: + return apiUsageState.getTbelExecState(); case EMAIL: return apiUsageState.getEmailExecState(); case SMS: @@ -171,6 +173,9 @@ public abstract class BaseApiUsageState { case JS: apiUsageState.setJsExecState(value); break; + case TBEL: + apiUsageState.setTbelExecState(value); + break; case EMAIL: apiUsageState.setEmailExecState(value); 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 307e2e5f3a..c02b7e9cc1 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 @@ -777,6 +777,21 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.6.0": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + if (isOldSchema(conn, 3006000)) { + log.info("Updating schema ..."); + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.6.0", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3006001;"); + log.info("Schema updated to version 3.6.1."); + } else { + log.info("Skip schema re-update to version 3.6.1. Use env flag 'SKIP_SCHEMA_VERSION_CHECK' to force the re-update."); + } + } 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/mail/DefaultMailService.java b/application/src/main/java/org/thingsboard/server/service/mail/DefaultMailService.java index 246fa4a0fa..ff54fb6e7a 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 @@ -362,6 +362,8 @@ public class DefaultMailService implements MailService { return valueInM + " out of " + thresholdInM + " allowed messages"; case JS_EXEC_COUNT: return valueInM + " out of " + thresholdInM + " allowed JavaScript functions"; + case TBEL_EXEC_COUNT: + return valueInM + " out of " + thresholdInM + " allowed Tbel functions"; case RE_EXEC_COUNT: return valueInM + " out of " + thresholdInM + " allowed Rule Engine messages"; case EMAIL_EXEC_COUNT: @@ -382,6 +384,8 @@ public class DefaultMailService implements MailService { return recordState.getValueAsString() + " messages"; case JS_EXEC_COUNT: return "JavaScript functions " + recordState.getValueAsString() + " times"; + case TBEL_EXEC_COUNT: + return "Tbel functions " + recordState.getValueAsString() + " times"; case RE_EXEC_COUNT: return recordState.getValueAsString() + " Rule Engine messages"; case EMAIL_EXEC_COUNT: diff --git a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java index c601be7272..d020fef1cb 100644 --- a/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/HomePageApiTest.java @@ -417,6 +417,9 @@ public class HomePageApiTest extends AbstractControllerTest { Assert.assertEquals(0, usageInfo.getJsExecutions()); Assert.assertEquals(configuration.getMaxJSExecutions(), usageInfo.getMaxJsExecutions()); + Assert.assertEquals(0, usageInfo.getTbelExecutions()); + Assert.assertEquals(configuration.getMaxTbelExecutions(), usageInfo.getMaxTbelExecutions()); + Assert.assertEquals(0, usageInfo.getEmails()); Assert.assertEquals(configuration.getMaxEmails(), usageInfo.getMaxEmails()); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java b/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java index 31d8b7aeea..84fe049ee9 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ApiFeature.java @@ -22,6 +22,7 @@ public enum ApiFeature { DB("dbApiState", "Telemetry persistence"), RE("ruleEngineApiState", "Rule Engine execution"), JS("jsExecutionApiState", "JavaScript functions execution"), + TBEL("tbelExecutionApiState", "Tbel functions execution"), EMAIL("emailApiState", "Email messages"), SMS("smsApiState", "SMS messages"), ALARM("alarmApiState", "Alarms"); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java index 64eabfdd16..4554ec8f5f 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageRecordKey.java @@ -24,6 +24,7 @@ public enum ApiUsageRecordKey { STORAGE_DP_COUNT(ApiFeature.DB, "storageDataPointsCount", "storageDataPointsLimit", "data point"), RE_EXEC_COUNT(ApiFeature.RE, "ruleEngineExecutionCount", "ruleEngineExecutionLimit", "Rule Engine execution"), JS_EXEC_COUNT(ApiFeature.JS, "jsExecutionCount", "jsExecutionLimit", "JavaScript execution"), + TBEL_EXEC_COUNT(ApiFeature.TBEL, "tbelExecutionCount", "tbelExecutionLimit", "Tbel execution"), EMAIL_EXEC_COUNT(ApiFeature.EMAIL, "emailCount", "emailLimit", "email message"), SMS_EXEC_COUNT(ApiFeature.SMS, "smsCount", "smsLimit", "SMS message"), CREATED_ALARMS_COUNT(ApiFeature.ALARM, "createdAlarmsCount", "createdAlarmsLimit", "alarm"), @@ -31,6 +32,7 @@ public enum ApiUsageRecordKey { INACTIVE_DEVICES("inactiveDevicesCount"); private static final ApiUsageRecordKey[] JS_RECORD_KEYS = {JS_EXEC_COUNT}; + private static final ApiUsageRecordKey[] TBEL_RECORD_KEYS = {TBEL_EXEC_COUNT}; private static final ApiUsageRecordKey[] RE_RECORD_KEYS = {RE_EXEC_COUNT}; private static final ApiUsageRecordKey[] DB_RECORD_KEYS = {STORAGE_DP_COUNT}; private static final ApiUsageRecordKey[] TRANSPORT_RECORD_KEYS = {TRANSPORT_MSG_COUNT, TRANSPORT_DP_COUNT}; @@ -75,6 +77,8 @@ public enum ApiUsageRecordKey { return RE_RECORD_KEYS; case JS: return JS_RECORD_KEYS; + case TBEL: + return TBEL_RECORD_KEYS; case EMAIL: return EMAIL_RECORD_KEYS; case SMS: diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageState.java b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageState.java index d28a8b0908..e6f3192194 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageState.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/ApiUsageState.java @@ -37,6 +37,7 @@ public class ApiUsageState extends BaseData implements HasTenan private ApiUsageStateValue dbStorageState; private ApiUsageStateValue reExecState; private ApiUsageStateValue jsExecState; + private ApiUsageStateValue tbelExecState; private ApiUsageStateValue emailExecState; private ApiUsageStateValue smsExecState; private ApiUsageStateValue alarmExecState; @@ -57,6 +58,7 @@ public class ApiUsageState extends BaseData implements HasTenan this.dbStorageState = ur.getDbStorageState(); this.reExecState = ur.getReExecState(); this.jsExecState = ur.getJsExecState(); + this.tbelExecState = ur.getTbelExecState(); this.emailExecState = ur.getEmailExecState(); this.smsExecState = ur.getSmsExecState(); this.alarmExecState = ur.getAlarmExecState(); @@ -78,6 +80,10 @@ public class ApiUsageState extends BaseData implements HasTenan return !ApiUsageStateValue.DISABLED.equals(jsExecState); } + public boolean isTbelExecEnabled() { + return !ApiUsageStateValue.DISABLED.equals(tbelExecState); + } + public boolean isEmailSendEnabled(){ return !ApiUsageStateValue.DISABLED.equals(emailExecState); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java index 9b03118bad..bdd9801b0c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/UsageInfo.java @@ -33,7 +33,9 @@ public class UsageInfo { private long transportMessages; private long maxTransportMessages; private long jsExecutions; + private long tbelExecutions; private long maxJsExecutions; + private long maxTbelExecutions; private long emails; private long maxEmails; private long sms; diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index bd2b80f10a..2e5c78f4ba 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -56,6 +56,7 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura private long maxTransportDataPoints; private long maxREExecutions; private long maxJSExecutions; + private long maxTbelExecutions; private long maxDPStorageDays; private int maxRuleNodeExecutionsPerMessage; private long maxEmails; @@ -94,6 +95,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura return maxTransportDataPoints; case JS_EXEC_COUNT: return maxJSExecutions; + case TBEL_EXEC_COUNT: + return maxTbelExecutions; case RE_EXEC_COUNT: return maxREExecutions; case STORAGE_DP_COUNT: diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java index 23274e863d..ad45891cda 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/AbstractScriptInvokeService.java @@ -25,11 +25,8 @@ import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; -import org.thingsboard.server.common.stats.TbApiUsageReportClient; -import org.thingsboard.server.common.stats.TbApiUsageStateClient; import java.util.Map; -import java.util.Optional; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.Executor; @@ -45,9 +42,6 @@ import static java.lang.String.format; public abstract class AbstractScriptInvokeService implements ScriptInvokeService { protected final Map disabledScripts = new ConcurrentHashMap<>(); - - private final Optional apiUsageStateClient; - private final Optional apiUsageReportClient; private final AtomicInteger pushedMsgs = new AtomicInteger(0); private final AtomicInteger invokeMsgs = new AtomicInteger(0); private final AtomicInteger evalMsgs = new AtomicInteger(0); @@ -59,11 +53,6 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService protected ScheduledExecutorService timeoutExecutorService; - protected AbstractScriptInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { - this.apiUsageStateClient = apiUsageStateClient; - this.apiUsageReportClient = apiUsageReportClient; - } - protected long getMaxEvalRequestsTimeout() { return getMaxInvokeRequestsTimeout(); } @@ -88,6 +77,9 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService protected abstract boolean isScriptPresent(UUID scriptId); + protected abstract boolean isExecEnabled(TenantId tenantId); + protected abstract void reportExecution(TenantId tenantId, CustomerId customerId); + protected abstract ListenableFuture doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames); protected abstract TbScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args); @@ -122,7 +114,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService @Override public ListenableFuture eval(TenantId tenantId, ScriptType scriptType, String scriptBody, String... argNames) { - if (!apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isJsExecEnabled()) { + if (isExecEnabled(tenantId)) { if (scriptBodySizeExceeded(scriptBody)) { return error(format("Script body exceeds maximum allowed size of %s symbols", getMaxScriptBodySize())); } @@ -137,7 +129,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService @Override public ListenableFuture invokeScript(TenantId tenantId, CustomerId customerId, UUID scriptId, Object... args) { - if (!apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isJsExecEnabled()) { + if (isExecEnabled(tenantId)) { if (!isScriptPresent(scriptId)) { return error("No compiled script found for scriptId: [" + scriptId + "]!"); } @@ -148,7 +140,7 @@ public abstract class AbstractScriptInvokeService implements ScriptInvokeService )); return Futures.immediateFailedFuture(handleScriptException(scriptId, null, t)); } - apiUsageReportClient.ifPresent(client -> client.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1)); + reportExecution(tenantId, customerId); pushedMsgs.incrementAndGet(); log.trace("[{}] InvokeScript uuid {} with timeout {}ms", tenantId, scriptId, getMaxInvokeRequestsTimeout()); var task = doInvokeFunction(scriptId, args); diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java index df84876869..192997f6a7 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/js/AbstractJsInvokeService.java @@ -23,6 +23,8 @@ import org.springframework.beans.factory.annotation.Value; import org.thingsboard.script.api.AbstractScriptInvokeService; import org.thingsboard.script.api.RuleNodeScriptFactory; import org.thingsboard.script.api.ScriptType; +import org.thingsboard.server.common.data.ApiUsageRecordKey; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.common.stats.TbApiUsageStateClient; @@ -39,6 +41,8 @@ import java.util.concurrent.ConcurrentHashMap; public abstract class AbstractJsInvokeService extends AbstractScriptInvokeService implements JsInvokeService { protected final Map scriptInfoMap = new ConcurrentHashMap<>(); + private final Optional apiUsageStateClient; + private final Optional apiUsageReportClient; @Getter @Value("${js.max_total_args_size:100000}") @@ -51,7 +55,8 @@ public abstract class AbstractJsInvokeService extends AbstractScriptInvokeServic private long maxScriptBodySize; protected AbstractJsInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { - super(apiUsageStateClient, apiUsageReportClient); + this.apiUsageStateClient = apiUsageStateClient; + this.apiUsageReportClient = apiUsageReportClient; } @Override @@ -59,6 +64,16 @@ public abstract class AbstractJsInvokeService extends AbstractScriptInvokeServic return scriptInfoMap.containsKey(scriptId); } + @Override + protected boolean isExecEnabled(TenantId tenantId) { + return !apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isJsExecEnabled(); + } + + @Override + protected void reportExecution(TenantId tenantId, CustomerId customerId) { + apiUsageReportClient.ifPresent(client -> client.report(tenantId, customerId, ApiUsageRecordKey.JS_EXEC_COUNT, 1)); + } + @Override protected JsScriptExecutionTask doInvokeFunction(UUID scriptId, Object[] args) { return new JsScriptExecutionTask(doInvokeFunction(scriptId, scriptInfoMap.get(scriptId), args)); diff --git a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java index 2a60980f84..221d68c33b 100644 --- a/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java +++ b/common/script/script-api/src/main/java/org/thingsboard/script/api/tbel/DefaultTbelInvokeService.java @@ -40,6 +40,8 @@ import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.script.api.AbstractScriptInvokeService; import org.thingsboard.script.api.ScriptType; import org.thingsboard.script.api.TbScriptException; +import org.thingsboard.server.common.data.ApiUsageRecordKey; +import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.common.stats.TbApiUsageStateClient; @@ -69,6 +71,8 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem protected Cache compiledScriptsCache; private SandboxedParserConfiguration parserConfig; + private final Optional apiUsageStateClient; + private final Optional apiUsageReportClient; @Getter @Value("${tbel.max_total_args_size:100000}") @@ -110,7 +114,8 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem private final Lock lock = new ReentrantLock(); protected DefaultTbelInvokeService(Optional apiUsageStateClient, Optional apiUsageReportClient) { - super(apiUsageStateClient, apiUsageReportClient); + this.apiUsageStateClient = apiUsageStateClient; + this.apiUsageReportClient = apiUsageReportClient; } @Scheduled(fixedDelayString = "${tbel.stats.print_interval_ms:10000}") @@ -167,6 +172,16 @@ public class DefaultTbelInvokeService extends AbstractScriptInvokeService implem return scriptIdToHash.containsKey(scriptId); } + @Override + protected boolean isExecEnabled(TenantId tenantId) { + return !apiUsageStateClient.isPresent() || apiUsageStateClient.get().getApiUsageState(tenantId).isTbelExecEnabled(); + } + + @Override + protected void reportExecution(TenantId tenantId, CustomerId customerId) { + apiUsageReportClient.ifPresent(client -> client.report(tenantId, customerId, ApiUsageRecordKey.TBEL_EXEC_COUNT, 1)); + } + @Override protected ListenableFuture doEvalScript(TenantId tenantId, ScriptType scriptType, String scriptBody, UUID scriptId, String[] argNames) { return executor.submit(() -> { 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 0e8ea2db15..278c2b094e 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 @@ -477,6 +477,7 @@ public class ModelConstants { public static final String API_USAGE_STATE_DB_STORAGE_COLUMN = "db_storage"; public static final String API_USAGE_STATE_RE_EXEC_COLUMN = "re_exec"; public static final String API_USAGE_STATE_JS_EXEC_COLUMN = "js_exec"; + public static final String API_USAGE_STATE_TBEL_EXEC_COLUMN = "tbel_exec"; public static final String API_USAGE_STATE_EMAIL_EXEC_COLUMN = "email_exec"; public static final String API_USAGE_STATE_SMS_EXEC_COLUMN = "sms_exec"; public static final String API_USAGE_STATE_ALARM_EXEC_COLUMN = "alarm_exec"; 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 b18f414c63..8b92002db5 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 @@ -64,6 +64,9 @@ public class ApiUsageStateEntity extends BaseSqlEntity implements @Column(name = ModelConstants.API_USAGE_STATE_JS_EXEC_COLUMN) private ApiUsageStateValue jsExecState = ApiUsageStateValue.ENABLED; @Enumerated(EnumType.STRING) + @Column(name = ModelConstants.API_USAGE_STATE_TBEL_EXEC_COLUMN) + private ApiUsageStateValue tbelExecState = ApiUsageStateValue.ENABLED; + @Enumerated(EnumType.STRING) @Column(name = ModelConstants.API_USAGE_STATE_EMAIL_EXEC_COLUMN) private ApiUsageStateValue emailExecState = ApiUsageStateValue.ENABLED; @Enumerated(EnumType.STRING) @@ -92,6 +95,7 @@ public class ApiUsageStateEntity extends BaseSqlEntity implements this.dbStorageState = ur.getDbStorageState(); this.reExecState = ur.getReExecState(); this.jsExecState = ur.getJsExecState(); + this.tbelExecState = ur.getTbelExecState(); this.emailExecState = ur.getEmailExecState(); this.smsExecState = ur.getSmsExecState(); this.alarmExecState = ur.getAlarmExecState(); @@ -111,6 +115,7 @@ public class ApiUsageStateEntity extends BaseSqlEntity implements ur.setDbStorageState(dbStorageState); ur.setReExecState(reExecState); ur.setJsExecState(jsExecState); + ur.setTbelExecState(tbelExecState); ur.setEmailExecState(emailExecState); ur.setSmsExecState(smsExecState); ur.setAlarmExecState(alarmExecState); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java b/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java index fcd75b25f7..7f4e065bd9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usage/BasicUsageInfoService.java @@ -67,6 +67,7 @@ public class BasicUsageInfoService implements UsageInfoService { usageInfo.setMaxAlarms(profileConfiguration.getMaxCreatedAlarms()); usageInfo.setMaxTransportMessages(profileConfiguration.getMaxTransportMessages()); usageInfo.setMaxJsExecutions(profileConfiguration.getMaxJSExecutions()); + usageInfo.setMaxTbelExecutions(profileConfiguration.getMaxTbelExecutions()); usageInfo.setMaxEmails(profileConfiguration.getMaxEmails()); usageInfo.setMaxSms(profileConfiguration.getMaxSms()); usageInfo.setSmsEnabled(profileConfiguration.getSmsEnabled()); @@ -75,6 +76,7 @@ public class BasicUsageInfoService implements UsageInfoService { Collection keys = Arrays.asList( ApiUsageRecordKey.TRANSPORT_MSG_COUNT.getApiCountKey(), ApiUsageRecordKey.JS_EXEC_COUNT.getApiCountKey(), + ApiUsageRecordKey.TBEL_EXEC_COUNT.getApiCountKey(), ApiUsageRecordKey.EMAIL_EXEC_COUNT.getApiCountKey(), ApiUsageRecordKey.SMS_EXEC_COUNT.getApiCountKey(), ApiUsageRecordKey.CREATED_ALARMS_COUNT.getApiCountKey()); @@ -82,6 +84,7 @@ public class BasicUsageInfoService implements UsageInfoService { List entries = tsService.findLatest(tenantId, apiUsageState.getId(), keys).get(); usageInfo.setTransportMessages(getLongValueFromTsEntries(entries, ApiUsageRecordKey.TRANSPORT_MSG_COUNT.getApiCountKey())); usageInfo.setJsExecutions(getLongValueFromTsEntries(entries, ApiUsageRecordKey.JS_EXEC_COUNT.getApiCountKey())); + usageInfo.setTbelExecutions(getLongValueFromTsEntries(entries, ApiUsageRecordKey.TBEL_EXEC_COUNT.getApiCountKey())); usageInfo.setEmails(getLongValueFromTsEntries(entries, ApiUsageRecordKey.EMAIL_EXEC_COUNT.getApiCountKey())); usageInfo.setSms(getLongValueFromTsEntries(entries, ApiUsageRecordKey.SMS_EXEC_COUNT.getApiCountKey())); usageInfo.setAlarms(getLongValueFromTsEntries(entries, ApiUsageRecordKey.CREATED_ALARMS_COUNT.getApiCountKey())); diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java index ba49cc964c..25d3c97c42 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/ApiUsageStateServiceImpl.java @@ -93,6 +93,7 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A apiUsageState.setTransportState(ApiUsageStateValue.ENABLED); apiUsageState.setReExecState(ApiUsageStateValue.ENABLED); apiUsageState.setJsExecState(ApiUsageStateValue.ENABLED); + apiUsageState.setTbelExecState(ApiUsageStateValue.ENABLED); apiUsageState.setDbStorageState(ApiUsageStateValue.ENABLED); apiUsageState.setSmsExecState(ApiUsageStateValue.ENABLED); apiUsageState.setEmailExecState(ApiUsageStateValue.ENABLED); @@ -110,6 +111,8 @@ public class ApiUsageStateServiceImpl extends AbstractEntityService implements A new StringDataEntry(ApiFeature.RE.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.JS.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); + apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), + new StringDataEntry(ApiFeature.TBEL.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), new StringDataEntry(ApiFeature.EMAIL.getApiStateKey(), ApiUsageStateValue.ENABLED.name()))); apiUsageStates.add(new BasicTsKvEntry(saved.getCreatedTime(), diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 72469e3bdd..d10be65a50 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -696,6 +696,7 @@ CREATE TABLE IF NOT EXISTS api_usage_state ( db_storage varchar(32), re_exec varchar(32), js_exec varchar(32), + tbel_exec varchar(32), email_exec varchar(32), sms_exec varchar(32), alarm_exec varchar(32), From bae0ce48a85a0caaf81e7de747e0567ebd30236b Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 21 Sep 2023 17:48:53 +0200 Subject: [PATCH 100/267] BaseController: log experience improvement. use a child class logger instead of abstract class controller --- .../org/thingsboard/server/controller/BaseController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 0af55d7c00..365f1fc379 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -21,7 +21,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; @@ -174,10 +174,11 @@ import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIEL import static org.thingsboard.server.controller.UserController.YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION; import static org.thingsboard.server.dao.service.Validator.validateId; -@Slf4j @TbCoreComponent public abstract class BaseController { + private final Logger log = org.slf4j.LoggerFactory.getLogger(getClass()); + /*Swagger UI description*/ @Autowired From 8cefca23acac97d2bc1be1787b2cccf98e6c0aaf Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Mon, 25 Sep 2023 11:27:00 +0300 Subject: [PATCH 101/267] Version set to 3.6.1-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/script/pom.xml | 2 +- common/script/remote-js-client/pom.xml | 2 +- common/script/script-api/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 +- common/version-control/pom.xml | 2 +- dao/pom.xml | 2 +- monitoring/pom.xml | 2 +- msa/black-box-tests/pom.xml | 2 +- msa/js-executor/package.json | 2 +- msa/js-executor/pom.xml | 2 +- msa/monitoring/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/vc-executor-docker/pom.xml | 2 +- msa/vc-executor/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 +- 58 files changed, 59 insertions(+), 59 deletions(-) diff --git a/application/pom.xml b/application/pom.xml index 9cc4ca8dd5..ee01bfbaf3 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard application diff --git a/common/actor/pom.xml b/common/actor/pom.xml index 2de85be932..7fa770c811 100644 --- a/common/actor/pom.xml +++ b/common/actor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/cache/pom.xml b/common/cache/pom.xml index 440860fda6..8ec12ca0e7 100644 --- a/common/cache/pom.xml +++ b/common/cache/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/cluster-api/pom.xml b/common/cluster-api/pom.xml index c9fa6d0894..1546121b77 100644 --- a/common/cluster-api/pom.xml +++ b/common/cluster-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/coap-server/pom.xml b/common/coap-server/pom.xml index 420fc4dae6..d4b54af0b5 100644 --- a/common/coap-server/pom.xml +++ b/common/coap-server/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/dao-api/pom.xml b/common/dao-api/pom.xml index 029c660500..3c735dd073 100644 --- a/common/dao-api/pom.xml +++ b/common/dao-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/data/pom.xml b/common/data/pom.xml index d3651c332a..ab1831a6e7 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/edge-api/pom.xml b/common/edge-api/pom.xml index 60562efbf2..71d6a42819 100644 --- a/common/edge-api/pom.xml +++ b/common/edge-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index e64d4676ce..2a8171ec72 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index 0edd153a3c..9e293cdd69 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index edd4574bdd..6a03c6bff3 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/script/pom.xml b/common/script/pom.xml index 26f60bd358..dcd5c6bc55 100644 --- a/common/script/pom.xml +++ b/common/script/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/script/remote-js-client/pom.xml b/common/script/remote-js-client/pom.xml index 8fa852d977..e0ad5ec3b1 100644 --- a/common/script/remote-js-client/pom.xml +++ b/common/script/remote-js-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT script org.thingsboard.common.script diff --git a/common/script/script-api/pom.xml b/common/script/script-api/pom.xml index c4e069f695..6680199616 100644 --- a/common/script/script-api/pom.xml +++ b/common/script/script-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT script org.thingsboard.common.script diff --git a/common/stats/pom.xml b/common/stats/pom.xml index 0869243e7a..6514b65b2a 100644 --- a/common/stats/pom.xml +++ b/common/stats/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index 2ac15d3e42..52758820cf 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index 8cf3e0efe8..bcd05edba4 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/lwm2m/pom.xml b/common/transport/lwm2m/pom.xml index 4433eae2b9..c2a5d8bd4b 100644 --- a/common/transport/lwm2m/pom.xml +++ b/common/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index bb4767640c..0baf8be935 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index 6879a4924d..be175ae817 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/snmp/pom.xml b/common/transport/snmp/pom.xml index 1865f498fa..be95664251 100644 --- a/common/transport/snmp/pom.xml +++ b/common/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.common - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 2e2174e0a9..ce4594be7d 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.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/util/pom.xml b/common/util/pom.xml index 14ae1748b2..3d37912ba1 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/common/version-control/pom.xml b/common/version-control/pom.xml index a8acdf2be9..a0811b1e1a 100644 --- a/common/version-control/pom.xml +++ b/common/version-control/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT common org.thingsboard.common diff --git a/dao/pom.xml b/dao/pom.xml index 420c72bd7d..e90694f22e 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard dao diff --git a/monitoring/pom.xml b/monitoring/pom.xml index 399e34092d..989cd113af 100644 --- a/monitoring/pom.xml +++ b/monitoring/pom.xml @@ -21,7 +21,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 12d36272c0..341bdbb560 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index dc72a2bb22..558eddd3e4 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.6.0", + "version": "3.6.1", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.ts", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 0bd7bf4d60..128479e5eb 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/monitoring/pom.xml b/msa/monitoring/pom.xml index ba96ada39c..092bcfccc8 100644 --- a/msa/monitoring/pom.xml +++ b/msa/monitoring/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa diff --git a/msa/pom.xml b/msa/pom.xml index bf4e15d9d4..fde5244ddf 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index 8437cc35c3..61185f4eda 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index 4fd630aafd..4f0d14aabb 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index 386b91ea76..404006d2fa 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 344219a660..2ba1a5cb73 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/lwm2m/pom.xml b/msa/transport/lwm2m/pom.xml index 8dfef617cd..3db99773c8 100644 --- a/msa/transport/lwm2m/pom.xml +++ b/msa/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index e1d740c877..3b67d74fee 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index e0bd5a9457..445ee31bf7 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/snmp/pom.xml b/msa/transport/snmp/pom.xml index b6a4e15b04..af3dc31629 100644 --- a/msa/transport/snmp/pom.xml +++ b/msa/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard.msa transport - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT org.thingsboard.msa.transport diff --git a/msa/vc-executor-docker/pom.xml b/msa/vc-executor-docker/pom.xml index 9b6fc493cd..3bca1a5c8d 100644 --- a/msa/vc-executor-docker/pom.xml +++ b/msa/vc-executor-docker/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/vc-executor/pom.xml b/msa/vc-executor/pom.xml index 9bd2befa90..4e6b6c4e11 100644 --- a/msa/vc-executor/pom.xml +++ b/msa/vc-executor/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 3338d2ae76..a1ac96937b 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.6.0", + "version": "3.6.1", "description": "ThingsBoard Web UI Microservice", "main": "server.ts", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index e9500cf5e0..cbee67c12e 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 962a9a8bbc..492d120d05 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,11 +19,11 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard netty-mqtt - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 6eba036d51..0344ced04e 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT pom Thingsboard diff --git a/rest-client/pom.xml b/rest-client/pom.xml index 638dc42009..8651656744 100644 --- a/rest-client/pom.xml +++ b/rest-client/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard rest-client diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index fe8cb3fab5..39e395b756 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 47d13e5658..9658f51e05 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.6.0-SNAPSHOT + 3.6.1-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 34c6e315f7..636f59ca5f 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.6.0-SNAPSHOT + 3.6.1-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/tools/pom.xml b/tools/pom.xml index c0b74bb0a9..5417f12119 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 3b1e0a9e62..c4b52361b7 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index 3d4b806d03..4e3abea0d1 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/lwm2m/pom.xml b/transport/lwm2m/pom.xml index efe76111f3..5bac4f5973 100644 --- a/transport/lwm2m/pom.xml +++ b/transport/lwm2m/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index 75daa483a1..67f27f8ab4 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 203ea6cbbb..4e0182928c 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard transport diff --git a/transport/snmp/pom.xml b/transport/snmp/pom.xml index c04e7d1f1f..da4c8c23d3 100644 --- a/transport/snmp/pom.xml +++ b/transport/snmp/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT transport diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 80ccca6050..805cfe267b 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "3.6.0", + "version": "3.6.1", "scripts": { "ng": "ng", "start": "node --max_old_space_size=8048 ./node_modules/@angular/cli/bin/ng serve --configuration development --host 0.0.0.0 --open", diff --git a/ui-ngx/pom.xml b/ui-ngx/pom.xml index d6dc28490f..84b5f8b98c 100644 --- a/ui-ngx/pom.xml +++ b/ui-ngx/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 3.6.0-SNAPSHOT + 3.6.1-SNAPSHOT thingsboard org.thingsboard From 25d3b96c6c2ce1405bb40048f145b08ff4749980 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 25 Sep 2023 13:57:21 +0300 Subject: [PATCH 102/267] text refactoring --- .../org/thingsboard/server/service/mail/DefaultMailService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 ff54fb6e7a..ba1b8cca75 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 @@ -385,7 +385,7 @@ public class DefaultMailService implements MailService { case JS_EXEC_COUNT: return "JavaScript functions " + recordState.getValueAsString() + " times"; case TBEL_EXEC_COUNT: - return "Tbel functions " + recordState.getValueAsString() + " times"; + return "TBEL functions " + recordState.getValueAsString() + " times"; case RE_EXEC_COUNT: return recordState.getValueAsString() + " Rule Engine messages"; case EMAIL_EXEC_COUNT: From 20ba944a3c6a82d498f5367f87225c339494d281 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 25 Sep 2023 16:30:45 +0300 Subject: [PATCH 103/267] fixed upgrade script --- .../thingsboard/server/install/ThingsboardInstallService.java | 4 ++++ 1 file changed, 4 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 208da7d36c..5ed009d4b6 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -262,6 +262,10 @@ public class ThingsboardInstallService { databaseEntitiesUpgradeService.upgradeDatabase("3.5.1"); dataUpdateService.updateData("3.5.1"); systemDataLoaderService.updateDefaultNotificationConfigs(); + break; + case "3.6.0": + log.info("Upgrading ThingsBoard from version 3.6.0 to 3.6.1 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.6.0"); //TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache break; default: From ff5582b948c8c2f9798cce2894f74f1fbac5dcd1 Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 26 Sep 2023 12:27:19 +0300 Subject: [PATCH 104/267] UI: Added tbel api limit config to tenant profile and updated api usage dashboard to display its status --- ...enant-profile-configuration.component.html | 26 +- ...-tenant-profile-configuration.component.ts | 1 + .../src/app/shared/models/api-usage.models.ts | 2 + ui-ngx/src/app/shared/models/tenant.model.ts | 2 + ui-ngx/src/assets/dashboard/api_usage.json | 490 +++++++++++++++--- .../assets/locale/locale.constant-ca_ES.json | 2 - .../assets/locale/locale.constant-cs_CZ.json | 2 - .../assets/locale/locale.constant-da_DK.json | 2 - .../assets/locale/locale.constant-en_US.json | 12 +- .../assets/locale/locale.constant-es_ES.json | 2 - .../assets/locale/locale.constant-fr_FR.json | 2 - .../assets/locale/locale.constant-ko_KR.json | 2 - .../assets/locale/locale.constant-sl_SI.json | 2 - .../assets/locale/locale.constant-tr_TR.json | 2 - .../assets/locale/locale.constant-zh_CN.json | 2 - .../assets/locale/locale.constant-zh_TW.json | 2 - 16 files changed, 461 insertions(+), 92 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html index c2872d4145..0445cce71c 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html @@ -169,15 +169,15 @@ - tenant-profile.max-transport-data-points + tenant-profile.max-tbel-executions - - {{ 'tenant-profile.max-transport-data-points-required' | translate}} + + {{ 'tenant-profile.max-tbel-executions-required' | translate}} - - {{ 'tenant-profile.max-transport-data-points-range' | translate}} + + {{ 'tenant-profile.max-tbel-executions-range' | translate}} @@ -196,7 +196,19 @@ -
+ + tenant-profile.max-transport-data-points + + + {{ 'tenant-profile.max-transport-data-points-required' | translate}} + + + {{ 'tenant-profile.max-transport-data-points-range' | translate}} + + + diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts index a4915f924b..6640f0bab0 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts @@ -81,6 +81,7 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA maxTransportDataPoints: [null, [Validators.required, Validators.min(0)]], maxREExecutions: [null, [Validators.required, Validators.min(0)]], maxJSExecutions: [null, [Validators.required, Validators.min(0)]], + maxTbelExecutions: [null, [Validators.required, Validators.min(0)]], maxDPStorageDays: [null, [Validators.required, Validators.min(0)]], maxRuleNodeExecutionsPerMessage: [null, [Validators.required, Validators.min(0)]], maxEmails: [null, [Validators.required, Validators.min(0)]], diff --git a/ui-ngx/src/app/shared/models/api-usage.models.ts b/ui-ngx/src/app/shared/models/api-usage.models.ts index bbc0ff5597..e6b1d86207 100644 --- a/ui-ngx/src/app/shared/models/api-usage.models.ts +++ b/ui-ngx/src/app/shared/models/api-usage.models.ts @@ -31,6 +31,7 @@ export enum ApiFeature { DB = 'DB', RE = 'RE', JS = 'JS', + TBEL = 'TBEL', EMAIL = 'EMAIL', SMS = 'SMS', ALARM = 'ALARM' @@ -41,6 +42,7 @@ export const ApiFeatureTranslationMap = new Map([ [ApiFeature.DB, 'api-usage.telemetry-persistence'], [ApiFeature.RE, 'api-usage.rule-engine-executions'], [ApiFeature.JS, 'api-usage.javascript-executions'], + [ApiFeature.TBEL, 'api-usage.tbel-executions'], [ApiFeature.EMAIL, 'api-usage.email-messages'], [ApiFeature.SMS, 'api-usage.sms-messages'], [ApiFeature.ALARM, 'api-usage.alarm'], diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 9074d599f5..8bc730010f 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -50,6 +50,7 @@ export interface DefaultTenantProfileConfiguration { maxTransportDataPoints: number; maxREExecutions: number; maxJSExecutions: number; + maxTbelExecutions: number; maxDPStorageDays: number; maxRuleNodeExecutionsPerMessage: number; maxEmails: number; @@ -102,6 +103,7 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan maxTransportDataPoints: 0, maxREExecutions: 0, maxJSExecutions: 0, + maxTbelExecutions: 0, maxDPStorageDays: 0, maxRuleNodeExecutionsPerMessage: 0, maxEmails: 0, diff --git a/ui-ngx/src/assets/dashboard/api_usage.json b/ui-ngx/src/assets/dashboard/api_usage.json index 5733b011f9..3c9259f453 100644 --- a/ui-ngx/src/assets/dashboard/api_usage.json +++ b/ui-ngx/src/assets/dashboard/api_usage.json @@ -21,7 +21,7 @@ { "name": "jsExecutionApiState", "type": "timeseries", - "label": "apiState", + "label": "jsApiState", "color": "#2196f3", "settings": {}, "_hash": 0.8830669138660703, @@ -29,12 +29,13 @@ "decimals": null, "funcBody": null, "usePostProcessing": true, - "postFuncBody": "return value ? value : 'ENABLED';" + "postFuncBody": "return value ? value : 'ENABLED';", + "aggregationType": "NONE" }, { "name": "jsExecutionLimit", "type": "timeseries", - "label": "limit", + "label": "jsLimit", "color": "#4caf50", "settings": {}, "_hash": 0.5463603803546802, @@ -42,12 +43,13 @@ "decimals": null, "funcBody": null, "usePostProcessing": null, - "postFuncBody": null + "postFuncBody": null, + "aggregationType": "NONE" }, { "name": "jsExecutionCount", "type": "timeseries", - "label": "count", + "label": "jsCount", "color": "#f44336", "settings": {}, "_hash": 0.5564241862015964, @@ -55,20 +57,8 @@ "decimals": null, "funcBody": null, "usePostProcessing": null, - "postFuncBody": null - }, - { - "name": "jsExecutionApiState", - "type": "timeseries", - "label": "apiStateClass", - "color": "#ffc107", - "settings": {}, - "_hash": 0.8737107059960671, - "units": null, - "decimals": null, - "funcBody": null, - "usePostProcessing": true, - "postFuncBody": "return value ? value.toLowerCase() : 'enabled';" + "postFuncBody": null, + "aggregationType": "NONE" }, { "name": "jsExecutionApiState", @@ -94,12 +84,13 @@ "decimals": null, "funcBody": null, "usePostProcessing": true, - "postFuncBody": "return \"{i18n:api-usage.javascript}\";" + "postFuncBody": "return \"{i18n:api-usage.udf-executions}\";", + "aggregationType": "NONE" }, { "name": "jsExecutionApiState", "type": "timeseries", - "label": "unit", + "label": "jsUnit", "color": "#8bc34a", "settings": {}, "_hash": 0.7926918686567068, @@ -107,7 +98,64 @@ "decimals": null, "funcBody": null, "usePostProcessing": true, - "postFuncBody": "return \"{i18n:api-usage.executions}\";" + "postFuncBody": "return \"{i18n:api-usage.javascript}\";", + "aggregationType": "NONE" + }, + { + "name": "tbelExecutionApiState", + "type": "timeseries", + "label": "tbelApiState", + "color": "#3f51b5", + "settings": {}, + "_hash": 0.950264191483049, + "aggregationType": "NONE", + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": true, + "postFuncBody": "return value ? value : 'ENABLED';" + }, + { + "name": "tbelExecutionLimit", + "type": "timeseries", + "label": "tbelLimit", + "color": "#e91e63", + "settings": {}, + "_hash": 0.9618078963734347, + "aggregationType": "NONE", + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null + }, + { + "name": "tbelExecutionCount", + "type": "timeseries", + "label": "tbelCount", + "color": "#ffeb3b", + "settings": {}, + "_hash": 0.26695276374882493, + "aggregationType": "NONE", + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null + }, + { + "name": "tbelExecutionApiState", + "type": "timeseries", + "label": "tbelUnit", + "color": "#03a9f4", + "settings": {}, + "_hash": 0.41720010909473104, + "aggregationType": "NONE", + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": true, + "postFuncBody": "return \"{i18n:api-usage.tbel}\";" } ] } @@ -141,8 +189,8 @@ "color": "#666666", "padding": "0", "settings": { - "cardHtml": "
\n \n \n
\n
\n
\n
${title}
\n
${apiState}
\n
\n
\n
${unit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n\n.card .mat-mdc-button-base {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mdc-button__label {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-mdc-button-base {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 10px;\n }\n .card .mat-mdc-button-base {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-mdc-button-base {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n\n" + "cardHtml": "
\n \n \n
\n
\n
\n
${title}
\n
\n
\n
\n
\n
\n
${jsUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
${tbelUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
", + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-mdc-button-base {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mdc-button__label {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-mdc-button-base {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-mdc-button-base {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-mdc-button-base {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n" }, "title": "JavaScript functions", "dropShadow": true, @@ -159,13 +207,17 @@ "actions": { "elementClick": [ { - "name": "javascript_functions_details", + "name": "user_defined_functions_details", "icon": "insert_chart", + "useShowWidgetActionFunction": null, + "showWidgetActionFunction": "return true;", "type": "openDashboardState", - "targetDashboardStateId": "javascript_functions", + "targetDashboardStateId": "user_defined_functions", "setEntityId": false, "stateEntityParamName": null, "openRightLayout": false, + "openInSeparateDialog": false, + "openInPopover": false, "id": "d4961bea-84de-e1af-e50f-666b98d34cd5" } ] @@ -1284,6 +1336,20 @@ "funcBody": null, "usePostProcessing": null, "postFuncBody": null + }, + { + "name": "tbelExecutionCountHourly", + "type": "timeseries", + "label": "{i18n:api-usage.tbel-executions}", + "color": "#4CAF50", + "settings": {}, + "_hash": 0.9298950525272727, + "aggregationType": null, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null } ] } @@ -1348,7 +1414,7 @@ "showTotal": true } }, - "title": "{i18n:api-usage.javascript-functions-hourly-activity}", + "title": "{i18n:api-usage.user-defined-functions-hourly-activity}", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -1362,11 +1428,15 @@ { "name": "{i18n:api-usage.view-details}", "icon": "insert_chart", + "useShowWidgetActionFunction": null, + "showWidgetActionFunction": "return true;", "type": "openDashboardState", - "targetDashboardStateId": "javascript_functions", + "targetDashboardStateId": "user_defined_functions", "setEntityId": false, "stateEntityParamName": null, "openRightLayout": false, + "openInSeparateDialog": false, + "openInPopover": false, "id": "4687d3f6-8800-a3b6-26e5-0d33f3b828a9" } ] @@ -4395,6 +4465,288 @@ "col": 0, "id": "aa875b7f-e7c8-7529-1ae7-f456211b59cc", "typeFullFqn": "system.charts.timeseries_bars_flot" + }, + "16d469c0-b3f5-d8a6-c62c-5c245c2cc865": { + "type": "timeseries", + "sizeX": 8, + "sizeY": 5, + "config": { + "datasources": [ + { + "type": "entity", + "name": null, + "entityAliasId": "40193437-33ac-3172-eefd-0b08eb849062", + "filterId": null, + "dataKeys": [ + { + "name": "tbelExecutionCountHourly", + "type": "timeseries", + "label": "{i18n:api-usage.tbel-executions}", + "color": "#4CAF50", + "settings": { + "excludeFromStacking": false, + "hideDataByDefault": false, + "disableDataHiding": false, + "removeFromLegend": false, + "showLines": false, + "fillLines": false, + "showPoints": false, + "showPointShape": "circle", + "pointShapeFormatter": "", + "showPointsLineWidth": 5, + "showPointsRadius": 3, + "showSeparateAxis": false, + "axisPosition": "left", + "thresholds": [ + { + "thresholdValueSource": "predefinedValue" + } + ], + "comparisonSettings": { + "showValuesForComparison": true + } + }, + "_hash": 0.0661644137210089, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null, + "aggregationType": null + } + ], + "alarmFilterConfig": { + "statusList": [ + "ACTIVE" + ] + } + } + ], + "timewindow": { + "hideInterval": false, + "hideAggregation": false, + "hideAggInterval": false, + "selectedTab": 1, + "history": { + "historyType": 0, + "timewindowMs": 2592000000, + "interval": 86400000 + }, + "aggregation": { + "type": "SUM", + "limit": 1000 + } + }, + "showTitle": true, + "backgroundColor": "#fff", + "color": "rgba(0, 0, 0, 0.87)", + "padding": "8px", + "settings": { + "shadowSize": 4, + "fontColor": "#545454", + "fontSize": 10, + "xaxis": { + "showLabels": true, + "color": "#545454" + }, + "yaxis": { + "showLabels": true, + "color": "#545454", + "min": 0, + "tickDecimals": 0, + "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;" + }, + "grid": { + "color": "#545454", + "tickColor": "#DDDDDD", + "verticalLines": true, + "horizontalLines": true, + "outlineWidth": 1 + }, + "stack": false, + "tooltipIndividual": false, + "defaultBarWidth": 1800000, + "barAlignment": "left", + "timeForComparison": "months", + "xaxisSecond": { + "axisPosition": "top", + "showLabels": true + }, + "showLegend": true, + "legendConfig": { + "direction": "column", + "position": "bottom", + "sortDataKeys": false, + "showMin": false, + "showMax": false, + "showAvg": false, + "showTotal": true + } + }, + "title": "{i18n:api-usage.tbel-functions-daily-activity}", + "dropShadow": true, + "enableFullscreen": true, + "titleStyle": { + "fontSize": "16px", + "fontWeight": 400 + }, + "widgetStyle": {}, + "useDashboardTimewindow": false, + "actions": {}, + "displayTimewindow": true, + "showTitleIcon": false, + "iconColor": "rgba(0, 0, 0, 0.87)", + "iconSize": "24px", + "titleTooltip": "", + "widgetCss": "", + "pageSize": 1024, + "noDataDisplayMessage": "" + }, + "row": 0, + "col": 0, + "id": "16d469c0-b3f5-d8a6-c62c-5c245c2cc865", + "typeFullFqn": "system.charts.timeseries_bars_flot" + }, + "70978475-c9d4-a54d-384a-851b4bba3917": { + "type": "timeseries", + "sizeX": 8, + "sizeY": 5, + "config": { + "datasources": [ + { + "type": "entity", + "name": null, + "entityAliasId": "40193437-33ac-3172-eefd-0b08eb849062", + "filterId": null, + "dataKeys": [ + { + "name": "tbelExecutionCount", + "type": "timeseries", + "label": "{i18n:api-usage.tbel-executions}", + "color": "#4CAF50", + "settings": { + "excludeFromStacking": false, + "hideDataByDefault": false, + "disableDataHiding": false, + "removeFromLegend": false, + "showLines": false, + "fillLines": false, + "showPoints": false, + "showPointShape": "circle", + "pointShapeFormatter": "", + "showPointsLineWidth": 5, + "showPointsRadius": 3, + "showSeparateAxis": false, + "axisPosition": "left", + "thresholds": [ + { + "thresholdValueSource": "predefinedValue" + } + ], + "comparisonSettings": { + "showValuesForComparison": true + } + }, + "_hash": 0.0661644137210089, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null, + "aggregationType": null + } + ], + "alarmFilterConfig": { + "statusList": [ + "ACTIVE" + ] + } + } + ], + "timewindow": { + "hideInterval": false, + "hideAggregation": false, + "hideAggInterval": false, + "selectedTab": 1, + "history": { + "historyType": 0, + "timewindowMs": 31536000000, + "interval": 1000 + }, + "aggregation": { + "type": "NONE", + "limit": 1000 + } + }, + "showTitle": true, + "backgroundColor": "#fff", + "color": "rgba(0, 0, 0, 0.87)", + "padding": "8px", + "settings": { + "shadowSize": 4, + "fontColor": "#545454", + "fontSize": 10, + "xaxis": { + "showLabels": true, + "color": "#545454" + }, + "yaxis": { + "showLabels": true, + "color": "#545454", + "min": 0, + "tickDecimals": 0, + "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;" + }, + "grid": { + "color": "#545454", + "tickColor": "#DDDDDD", + "verticalLines": true, + "horizontalLines": true, + "outlineWidth": 1 + }, + "stack": false, + "tooltipIndividual": false, + "defaultBarWidth": 900000000, + "barAlignment": "left", + "timeForComparison": "months", + "xaxisSecond": { + "axisPosition": "top", + "showLabels": true + }, + "showLegend": true, + "legendConfig": { + "direction": "column", + "position": "bottom", + "sortDataKeys": false, + "showMin": false, + "showMax": false, + "showAvg": false, + "showTotal": true + } + }, + "title": "{i18n:api-usage.tbel-functions-monthly-activity}", + "dropShadow": true, + "enableFullscreen": true, + "titleStyle": { + "fontSize": "16px", + "fontWeight": 400 + }, + "widgetStyle": {}, + "useDashboardTimewindow": false, + "actions": {}, + "displayTimewindow": true, + "showTitleIcon": false, + "iconColor": "rgba(0, 0, 0, 0.87)", + "iconSize": "24px", + "titleTooltip": "", + "widgetCss": "", + "pageSize": 1024, + "noDataDisplayMessage": "" + }, + "row": 0, + "col": 0, + "id": "70978475-c9d4-a54d-384a-851b4bba3917", + "typeFullFqn": "system.charts.timeseries_bars_flot" } }, "states": { @@ -4566,40 +4918,6 @@ } } }, - "javascript_functions": { - "name": "{i18n:api-usage.javascript-functions}", - "root": false, - "layouts": { - "main": { - "widgets": { - "5f5ca59c-e507-5301-5910-7ad8cd34df40": { - "sizeX": 24, - "sizeY": 6, - "row": 0, - "col": 0 - }, - "ada32ee9-44ed-48d1-c368-fd0c94b7607f": { - "sizeX": 24, - "sizeY": 6, - "row": 6, - "col": 0 - } - }, - "gridSettings": { - "backgroundColor": "#eeeeee", - "color": "rgba(0,0,0,0.870588)", - "columns": 24, - "margin": 10, - "backgroundSizeMode": "100%", - "autoFillHeight": true, - "backgroundImageUrl": null, - "mobileAutoFillHeight": false, - "mobileRowHeight": 70, - "outerMargin": true - } - } - } - }, "telemetry_persistence": { "name": "{i18n:api-usage.telemetry-persistence}", "root": false, @@ -4755,6 +5073,52 @@ } } } + }, + "user_defined_functions": { + "name": "{i18n:api-usage.user-defined-functions}", + "root": false, + "layouts": { + "main": { + "widgets": { + "5f5ca59c-e507-5301-5910-7ad8cd34df40": { + "sizeX": 12, + "sizeY": 6, + "row": 0, + "col": 0 + }, + "ada32ee9-44ed-48d1-c368-fd0c94b7607f": { + "sizeX": 12, + "sizeY": 6, + "row": 6, + "col": 0 + }, + "16d469c0-b3f5-d8a6-c62c-5c245c2cc865": { + "sizeX": 12, + "sizeY": 6, + "row": 0, + "col": 12 + }, + "70978475-c9d4-a54d-384a-851b4bba3917": { + "sizeX": 12, + "sizeY": 6, + "row": 6, + "col": 12 + } + }, + "gridSettings": { + "backgroundColor": "#eeeeee", + "color": "rgba(0,0,0,0.870588)", + "columns": 24, + "margin": 10, + "backgroundSizeMode": "100%", + "autoFillHeight": true, + "backgroundImageUrl": null, + "mobileAutoFillHeight": false, + "mobileRowHeight": 70, + "outerMargin": true + } + } + } } }, "entityAliases": { @@ -4809,4 +5173,4 @@ }, "externalId": null, "name": "Api Usage" -} \ No newline at end of file +} diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 0b7b09d15b..a2e8cb4c42 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -677,9 +677,7 @@ "executions": "Execucions", "javascript": "JavaScript", "javascript-executions": "Execucions JavaScript", - "javascript-functions": "Funcions JavaScript", "javascript-functions-daily-activity": "Activitat diària de funcions JavaScript", - "javascript-functions-hourly-activity": "Activitat horària de funcions JavaScript", "javascript-functions-monthly-activity": "Activitat mensual de funcions JavaScript", "latest-error": "Últim error", "messages": "Missatges", 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 c82ba68649..048b421a4e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -488,9 +488,7 @@ "executions": "Zpracování", "javascript": "JavaScript", "javascript-executions": "JavaScript výjimky", - "javascript-functions": "JavaScript funkce", "javascript-functions-daily-activity": "Denní aktivita JavaScript funkcí", - "javascript-functions-hourly-activity": "Hodinová aktivita JavaScript funkcí", "javascript-functions-monthly-activity": "Měsíční aktivita JavaScript funkcí", "latest-error": "Poslední chyba", "messages": "Zprávy", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 834cc15619..c318726315 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -493,9 +493,7 @@ "executions": "Udførelser", "javascript": "JavaScript", "javascript-executions": "JavaScript-udførelser", - "javascript-functions": "JavaScript-funktioner", "javascript-functions-daily-activity": "JavaScript-funktioners daglige aktivitet", - "javascript-functions-hourly-activity": "JavaScript-funktioners timeaktivitet", "javascript-functions-monthly-activity": "JavaScript-funktioners månedlige aktivitet", "latest-error": "Seneste fejl", "messages": "Beskeder", 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 0867f21114..50676ea044 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -770,12 +770,17 @@ "email-messages-monthly-activity": "Email messages monthly activity", "exceptions": "Exceptions", "executions": "Executions", + "udf-executions": "UDF executions", + "user-defined-functions": "User-defined functions", + "user-defined-functions-hourly-activity": "User-defined functions hourly activity", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions": "JavaScript functions", "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-hourly-activity": "JavaScript functions hourly activity", "javascript-functions-monthly-activity": "JavaScript functions monthly activity", + "tbel": "TBEL", + "tbel-executions": "TBEL executions", + "tbel-functions-daily-activity": "TBEL functions daily activity", + "tbel-functions-monthly-activity": "TBEL functions monthly activity", "latest-error": "Latest Error", "messages": "Messages", "notifications": "Notifications", @@ -3991,6 +3996,9 @@ "max-j-s-executions": "JavaScript executions maximum number ", "max-j-s-executions-required": "JavaScript executions maximum number is required.", "max-j-s-executions-range": "JavaScript executions maximum number can't be negative", + "max-tbel-executions": "TBEL executions maximum number ", + "max-tbel-executions-required": "TBEL executions maximum number is required.", + "max-tbel-executions-range": "TBEL executions maximum number can't be negative", "max-d-p-storage-days": "Data points storage days maximum number", "max-d-p-storage-days-required": "Data points storage days maximum number is required.", "max-d-p-storage-days-range": "Data points storage days maximum number can't be negative", 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 143bed648b..6bcd707bfc 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -715,9 +715,7 @@ "executions": "Ejecuciones", "javascript": "JavaScript", "javascript-executions": "Ejecuciones JavaScript", - "javascript-functions": "Funciones JavaScript", "javascript-functions-daily-activity": "Actividad diaria de funciones JavaScript", - "javascript-functions-hourly-activity": "Actividad horaria de funciones JavaScript", "javascript-functions-monthly-activity": "Actividad mensual de funciones JavaScript", "latest-error": "Último error", "messages": "Mensajes", 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 39d6646854..acf547354e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -488,9 +488,7 @@ "email-messages-monthly-activity": "Activité menuselle de courriels", "executions": "Exécutions", "javascript-executions": "Exécutions JavaScript", - "javascript-functions": "Fonctions JavaScript", "javascript-functions-daily-activity": "Activité hebdomadaire de fonctions JavaScript", - "javascript-functions-hourly-activity": "Activité horaire de fonctions JavaScript", "javascript-functions-monthly-activity": "Activité mensuelle de fonctions JavaScript", "latest-error": "Dernière erreur", "notifications-email-sms": "Notifications (Coourriel/SMS)", 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 aad25e9c0e..387a553506 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -447,9 +447,7 @@ "executions": "Executions", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions": "JavaScript functions", "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-hourly-activity": "JavaScript functions hourly activity", "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "latest-error": "최근 오류", "messages": "메시지", 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 c6a20b9a36..33fa10fbb4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -447,9 +447,7 @@ "executions": "Executions", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions": "JavaScript functions", "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-hourly-activity": "JavaScript functions hourly activity", "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "latest-error": "Latest Error", "messages": "Messages", 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 b377c9fd45..3819fb306f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -488,9 +488,7 @@ "executions": "Çalıştırmalar", "javascript": "JavaScript", "javascript-executions": "JavaScript çalıştırmaları", - "javascript-functions": "JavaScript fonksiyonları", "javascript-functions-daily-activity": "Günlük JavaScript fonksiyonları", - "javascript-functions-hourly-activity": "Saatlik JavaScript fonksiyonları", "javascript-functions-monthly-activity": "Aylık JavaScript fonksiyonları", "latest-error": "Son Hata", "messages": "Mesajlar", 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 895499e067..7cc76818cf 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -715,9 +715,7 @@ "executions": "执行数", "javascript": "JavaScript", "javascript-executions": "JavaScript 执行数", - "javascript-functions": "JavaScript 函数", "javascript-functions-daily-activity": "每天执行的JavaScript函数", - "javascript-functions-hourly-activity": "每小时执行的JavaScript函数", "javascript-functions-monthly-activity": "每月执行的JavaScript函数", "latest-error": "最新错误", "messages": "消息", 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 bb655f65e7..75086fb2cb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -563,9 +563,7 @@ "executions": "執行", "javascript": "JavaScript", "javascript-executions": "JavaScript執行", - "javascript-functions": "JavaScript功能", "javascript-functions-daily-activity": "JavaScript功能每日活動", - "javascript-functions-hourly-activity": "JavaScript功能每小時活動", "javascript-functions-monthly-activity": "JavaScript功能每月活動", "latest-error": "最新錯誤", "messages": "訊息", From bf5e9f0917f820aebfbbe3a89aa79ad09e512f31 Mon Sep 17 00:00:00 2001 From: kalytka Date: Wed, 27 Sep 2023 10:29:47 +0300 Subject: [PATCH 105/267] Updated rulenode examples png --- .../examples/customer-attributes-ft.png | Bin 88911 -> 29423 bytes .../examples/originator-attributes-ft.png | Bin 86148 -> 30258 bytes .../examples/originator-fields-ft.png | Bin 75513 -> 23958 bytes .../examples/originator-telemetry-ft-2.png | Bin 128981 -> 44951 bytes .../examples/originator-telemetry-ft.png | Bin 114627 -> 39394 bytes .../examples/related-device-attributes-ft.png | Bin 93697 -> 37267 bytes .../examples/related-entity-data-ft.png | Bin 113138 -> 38232 bytes .../examples/tenant-attributes-ft.png | Bin 87964 -> 29138 bytes 8 files changed, 0 insertions(+), 0 deletions(-) diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/customer-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/customer-attributes-ft.png index 43711a83701427ebaa0a02b514b922f01061b9a8..e9b35388124f25ac4fca652314389c0e29759649 100644 GIT binary patch literal 29423 zcmb??bzB@zknaLPf(H)-cXxLQuFEd&5?~1)Ah-q%9yGY`;BLVQ?yzWZ2(V~KfB=!l z@9y5`p4{ELKi+(LX1aT-y6RKa^PQTSo>*ON6+CQ8Y!C>9r>3d|27%B35a@{q7TRME z?XNg(5D3*lR}=E`@87@QuYZD|p|?NpcXoCzFE1&ns1lP>tgUVS{P|N*Q1I~ZU}x`e zeSLj&bmZgXb9;OH`}c4ASB~`b^t=0CdwO~=E-o@MGWPfPFR!lk^z?#5LJ&*KadB~X zcX!3bB{a0O8=IRcsi~ZtoNMdr)6+9;ZEXjK$MNqIoL{@Csj11x$OsFIoSa>FzVSgK zkvBI#(>|o%-T!KCZvOc3V|aMP)zy`wqf=*RrxWZo3kyqse}7a|R903N$RcWCacOvD zbY*pYa&oGsrsnF$ZFEfR{K7(AUESx;!(w9MjEsz1Tic~&WoH*xCUF&xPR=|$Jhcr? zN=iyvT3QR6hh3j~Lc_wdvU4jc;r#ppB5yJyBctBFeaptic7!}FC@elZI|G?UtR0-r z&dv=E4Jjxnj89DNeLdRT*=uNMV0xVbG77H*suL0tp-_X9%j@OkmAw4I^o%V3z~JiI z`p=7-y?ukDW8-iA1A~HsJUu-tdS^<@D&0KZn3$M+J^dD0(Vd%{FC`^4I5h0)=8@ez zlJha&+t)9)s+Z3*-QVATba^|aZZNF0tD&i7dG~nz%LcV$()RXt-`tn!^*sOp)I$n5 zT+=|-u|9A8b;67N3)`z|>Z<$aB;V$^xVUsqt~R%{xo0<$zDlr604yynA9d>M>swu2 zZ5vyb56DeUPA=@2@bwEgKR-`z{QNer<#l?!epKo9@kPm}srHUf!Nr{$U(fQ|#*WUv zC)D&u!+UI#YhccCc8W@gXq-(%avsRZS>w03k)uQ{dFd4Fta9$Vf$xojR;49zG5 z34yu64wnPoIv|j{qMDLCj)k#d_?zizs2GY;Dq4kgsUXtTynt(3UU!NMSFL;MdE zq0^=*9NY3Nf8e2LaNJO|QtWm)AQb2S$4QQHPKZ`!lGvFXj+!v3666wOCSw{O4p){w z9zqfwk83#Vn^GhHZ)`Eqfj=9zz{C>jTl4@`9&sq14U3Yg|p)SB1 zeJ`?J0pTs>#Buy|p$crFE3y-mns5)02OQ3P6d@emp{--BA};BDc|g!NG`Y`C_5Ry- zY;3=AvRo+FlVYsMcXSHscCiY&vHDRY!cTu2Ol^ou|B5Eb0m?{ch&;wN0w`qbEDLzY zdPiDNmGdYNcof8InHZga!XuepO?|jL=9c+Cf>U$m!RNXv4P9#cG@VmqV3m63G{*c+ey-{_Mq;+RuI{QV$90ZSXkpARZVr||hh zXLu{>-3Dlpx=@0;x6AN`wF;5c6c?xU0G!II0&tKKE1R|J1sY>0B)1)TKHJ*CwkgaR zJYAf%iJG>ik)jr9Y?Qfd%k%Rl@d5b6;jr z0ehTUO?ZM2GEchFHOV>5t1G=_T+Xu6qBA?C*nzhWvVsB=xCv|ljth`~*`Imx^|w{eg8 z3~z-WEr;)}eMi!GXJw(D9)l4||B1c9fVmj9UKUsk>|(=+YM>;o6`jwC4_vIY-#q;i zNH5Tfx?uF4W;-eNJg9U;sbHvsTGxgw6Q_@bED*1hgFrtoVP{&S&#H$d2koZ`?NOgY z5y$J9z3HEu3TW6QQ+V9x$s7>8#j~Uy6cgpd^^a6?wifBe8bI6+Xf~ceJisAYvxQP~ zOgJk`XfIT`sW^x_{$`ir?!624SB(gp`OPolYVT_6v0W;`FZO(v^0dM|%DC8=k*=Ki> zKfi;j$BK7=r{Jmwpad z6eirBf1GVjNLQ$+95mO=U-=7ATLw@UzAXfJn3|qIAC#PqhTteCj_<2aWeWLp`qQ^w zBy~OQzXqRcye+$VW<+RT6&xA-D_&Ou*XH!>D!uN|lQSr3O`*12^>IteyMBY-YIz>4_iEgSTUJ zE-py=XqY~?k@ppUVpIzU8bLj3Y@seoWG{2N^`ZCM9#yanJE-Xx5ap$4hCtnheuv2F zBE~oY5jyLsjkqv}Q^7~$1P&8O{W0Dp&rCnxY_7J0$&Kx?>3;My9y z2|cJ9+O&nCH`e>`H&!ogMyb@~KY_Fjpt=V*@Mx00Ja^X^cqhKA%t>zph~~4#!?#Hg z?&H|65wQ^#yb0tzG>#k(S5eWz;)Qe?R~XBOLFuD`sJPZ6;Zp`W5O0S3Rx@B7@R#eF z_~aoW2{A{RsHOPyBHrVv-Rj+jOHeTud4C#Jo6#?dG2*-99}Mk*ltuQ;4+r7D`Hi93 zR7B7`^hTXq11JyYy9zeRj?jV%^7{p+%{Rc1-EcH|x=DP#4uMFZa}7 zux(O0iw=(2o}l@ZO62>4jP>F;7w8C?7591mgVCKG6ppuY(1~Jn`;9_auHXx|P+x*{ z^)u@HP(2|XBVAc6ytPlmBw)$i(9Vm(E!HZ^aXb&GSKmAn0FzTpoJg9tZv0{dX^?b%%{4Dn@>hC{c2gYT4-Y>@#YLz=gxx}m zey#)aE$E3$CDcG7&bD10JI!7Xo_44FQ&YOY+V;GshfjH;p~k|mx5L|m$NLy_(2&rw zQa+V5DBfXI7LZM1wYUnZ9QE)!w&J~40~mf^x1w*;=ZxD`YE`)y_`tsIbb@?Mv07{C zyU97>l;#6hzr$fH<8>QRddfdJVq&nRX|~qUFe?#%@bo)&xIzB!Li9cxplTa;lKP+7 zrwPr8MG5R%r}3T2VO0YtB`DI2IMVVQKVXbFxoUZM`CEBaS9@b2?HIO?mqVV`s?~j~ z`{Pn}vf}gG;d909oK$}q$E$_awHPr(Q8~#Si1=@wf!VV&1L#)_I8bUBSVvWYZxuP5 zC+m>up9=V%^HoU}*uXV?Yz9AwbiVrWedx%{*y(fSo8zH|tGql(5o-#pa5n#3hQ0j7 zbXye+^6iyaXqa>IJrUcpIFc8blyB>zXOtx;&fKBv785$^T3V#FR+QuYQcD)4*myk! zjZ~X0v~Y#AV-MbshbM-TsT@L-e_6Uv;0k1Lg(v@ciA)cYC`18)xZmT>a@A)dM70&@KiKE1OB8 zxzHdyf|_aGwa8h8w$N6kqQ^*YIh@wx>Fux0otd4`%55Rx|HfgPR#`9wq~sU*Te<>_knCeMrRx8&@Fpu0DiE@8`Abyha94y?$n-<4il*xhkmKh{%VU!)_ zcooF&j0+m%4r-Pr%u9rSRTGA-4vQePkLWGhiY)EHwdyk4w+z|bm@yfgPv`Isb)>33 zVCqk$0jG5n>yU(*{Wj!}B1!gS31PZ?yrFk4Ij{CMB53?u@D0B{C;G5;|~+*XOtJRy*0rW=o}sBs5a!T=$`$< zni>E+og{{;e=#e?MU8-}p?Yay9uL-WH_*{)(cIBu(f%c;`@8*haY(gSjK=M_7UwXw zbOCq9TkVr6-@`9nyo>1^KRdg{BPI zd^AKfto9K09l30`ha{ci>ndsqFEY$RzI#PiEKgD0L#*pZ{>ohVKY4L`k+Ok;8yPnf zCeikXhVFwU?em;p7;R)U3+h`mPulqp&?xYDe@O4L_I~*rdWzrYp_TZrM+#?VNgQ{x zG{MT|mX5f;qzUhcv=Fo#IY22lRLVD~f6%VHzy+B5 z^v4*Q8whj3fb3QgU;M#G24}vhV#*fmD0~D@m5earMG*h>_A!f=_v!ctastU!%=_Z95M#`pgDf%n5jA;uPInsf9>Xj5H%K&`-$5x(ls}Bufm4ed*J>a805^ zcm-{JHa`Y-NyB)$%6dNixo237#I7N*7WwJ_H4?11qQHm}sL z0Sa2e5%y(KWfJj|M4;DVdyRz9tvd`*9%~vH{uzY}VeM>SK^+x`3l8%PYl^GXw6L-j zAkYv~^2(cx?f0hD?ZGT-7a&FbEl2U4!^X3axG)DM!;De!E30mLXKQE1B@H+zv#LJa z^r6~zNPTCtmpP9AD+n+!2O7T7X}ouv5B>D-ydU2^w@N| z$xYIr3nPr*znQV$&H5`I9TLyprUmp$8JMhpHG*66)K8tuY)nzM9-Ix zb)NM*I zF-AlR(L?(@!%kPfJ3+fJNKoW;T7{RCONpzHj#fNfC33~sSOriV@+V1!Q zr_D-rMPuHMR|hzMlCklAZSfLwo%kr6R1;og+al^52=mMyTyRAnjHHzNZtZIqTAnlY zv%CMNvqGY3*(C%_v{GZZdInY6gG`7z<99WkzM9fwcPL0*1=i|fYKH_hg`^OuoywI& zn_&HoKGs5;5%ta{`ri#;K2z$wzO3W!lST(J57=sF9Vu&k7 z!m%n5g@h&*I+7fYyGB`Jf*&HmXt{%N_QHth6;xnL=bFx7XoZ0I`Ow|R`!Gxonk?oY zhTxz+pS1&s@S{+WUdu=Bes;{d++;NN{VcUgW|UdX5J zY*f!N+RLmg9#w3894?c&vjgE?QC8KRzIaiYoPgzAijSv3I&Jl}h7;N&lh?n0n0*z5 zNUH^z^s^yQ$yjjpsX47&ZRi>2A<_0uEi)WrG{5CWq{<&UKaXlvmSP+7J$Ul4+x|2D zdoaQ^>>-JS{9S>W%k6!arsU2-(2dm28Ux^Pb73{^R{ zEq5Ffj!GCMjjDP>zWppdM8yabWf8Jtt&Xj2-v8+p{>XE>djoFjkyBVTPk>vry~Brb zS(E7?hYNgdVyp;0+?f|lqm8>FgnTQZ$*7*VD{|wiIP45AMkQ6EtJq%)4v%*Zx~4wd zrXtsn-+b=x@45obWd8Q*wCz0z4Kr^??(TjLHjei8ZO;#xSsrxFTjbY{S5Loh4dE;I zHaYaO!1Sj4+TH_U=e40a5s>EEi{yYJ<7<8|=q7EKs{73;DtP?2_dzNW@_!E#A8UPi z)RN8CbQs}mo!cv8!^+D80=JeXZ%gZ2K4@*8>_j~OU#PclPtC}6-3}53W+pu_buVbd z3jpvk{`QCNIFmf}cWF0VYjBiYNRy%06ZiR1wt6Xb_oeRQKGHr1OZ{xfP6A{{R*lpo znWLEw>L?G)hC_9N5?0(CF>d-nuO|1tvN5bsI8jCTz>{k4HpLEouSK%=h81!` zF%`&bX2Hn%4)}4htAtQY7G;4}_v8<)oF$7kkqw_vYJ@0wlghS^EPQ%*VCszpJzoAC z4S+wz$>07kzz^vPSe*DP3A`-rh^KWHNT4g?_}xjN=baW9C9m=6btTWIlMaLeYUtDq zCiQ_dM*Xv9+HRBL&kDc z3d=pi9b0gkK}t<%i~LKbUO^jLy~fVx8VCmWjOU#U zNvL)FzT)(=l1iD(LP*CTHq(?mVTH|S_4cCEmD7viDC-g>Cgs{rz}6wtqjaqgSqoHU zfpUnidKiYJv`14*xN&N&@j1vq>=S${MSu%!rc$7N-+kBFXW=>6oOwAen_B{>uVfa* zJzG1--?Ly73lV+F%(r~t;01a?vkYO4%knywQJ5>o<7&I(NpYF&h(z^kf55=v=JyA^ zuB2&bw3c?d3M+ykjKmvUMUSKZMU5#pXFlJzm&}DZqYfx*-AYDCH|YdJhO_fPp4OZ5<)pFG~c{P)i{Lc$IakDYs#b* zu7Rkxs#J^+=UmayQ$2v%B8*-0nz+OFdk;DVu=C9eP?36)yp%*!??iyS0-^iQzRQdO z*QEWiDjb$p^iG4VnHfkFq_vHv?aF&IB5eM$2V~(?-i-aO>B^&rGEV9uWDoTK;!jfQ zEn`~0i~5jk&`cdhh;TFZn8}tdHFXmBcVAO^6l73C3GRATonN$Og&75N)K0aL^F~2G zU;p(UUCX<35H)n%7swcNK7<^GxYZ$(8VnIGr7n+#l@OpQlMwzPUP@`fpni>#t)gpJ zN12mWDyADWBhMNIbhJiFD_(zSyh0ak5eF4`upKx;Ttb~` zw6jN1zq{)PRv)_|E+XX{8$u{g{P&Sv49qc>4IyeL>+Y|7EpxY&TNQQ4#EuWyNfW_E zKr%VAC(S8=4a8yswsS`LJ-wSbqi6}lfh0|ERSO>;%y5|b9rI0XBDiLOy@D*Q8kL&n z%r0Ld2bfyG6`*OmCjQArOp^qj@-^7C<^-`+Qs)W|lZ6X1hIXFG^h2RmHGQ6B+I;1Xcd9fo0$(T9S z&GHeakNIWmz@8q!#yL-adqocvF&9HbCHm!VJB#9S2j$K0cf{4=&=J&SSBH>_f(y8X zZCrl2zgZ=FU1BKAb&H$&9Ha-d8$i38r_PGTDtgwNCw_);#2HFKb7l)n697OYQ5gEk z*r{rB@hL_(Afhw)D6H@Npnm~p0!t5%`&n7sSVRUuoxlB_!}Go_eg21{SL&NN_#c6f zO?=rC>ar7!KeVFj=+*vuljk9ul2}J4Q@fH&|90YNBd*3$61f0AKZ=htHGWAsdNuvh9T&T$R{3z(6=q|NpMSPS+an2KWfyS)Y^| zDjhL7gmIy$AIl%jvv?232%t#5MOSY{4JX7465D+6`DywT@b7*PcNM^kA_)`x(FYcsdxOdfQlkHDUFO&LW3 z7>Vt7MMB^VBu0P6C=pmeeY(cs1mIiI#A+|L2}~y^*LapAK|D`*7v0Knm~5&(zX zEBSy}c-A$>PBZ`sD8z65C@FdSFt79i)BV@NvJ8RG{2a}jEj$d{`t##mpP~MCVG}X= z7%f7`9g?Yi=Z0G*yvLRlOlV1ywl|n#O=xQ)Dm9t0U~kzp?^7V z>+Et2r}x%5;4<#l#jww19nKueuNKE0!gZgH_X*fV+Lc$*1%8J8T7F3|Sq7Ha28xnivk%;b`5VH%Dvbwdz#O}SJny)Uiq=TBU-Ek`Y zp5OQ`i$(@JvlyK6qpm%dz5$t^$G8nG?vS@Mk7y;$E6!IE;S?oQfNS{-Z>g4(qLa4J zO`vLmT2nPmRSQ#H9@-5JqADh_@$Hr@&c(`%u+;`J<9Zg=w<%VXxcA7fO9`AGPa-G# zO^eIs2iJz;8^Ko{-`#eZ{&%{qswF zg=wF~QN=II9Ck6U4hG)6FqNg1cOKQjQfx(EJ&jl95koy{oLR+raQi7R zXid@rmd$Vh$&%=yqx2f`kvQu< z8y17)@G-ftNpS8w+V@6Ci!oGpZrx@{VYs}HX-G#d3VO0)#oLkJjEp+d8s6jOH?_fj zna4Y;5$*Syh7pvu@O0I}KKKa?!%gZnDR+B6atWFUWvXvrkGO}HPeh~+C7TzoI^AFU<`+Gy?(_Ck+3dV%OVVL1#c`p|Eqnnfx44(pZCesDbjjRYmkc_V`o^J zzZHzQ|NJ@US_Z2JMLT`U`Sz(F7GD#=q4Jo(4{B)9Ot5uJ)wu!DOa51oH{SHV)Ovba z@w`#oO~vE8n=$HAp)rm2u7zxrOV5!-?`s_x*eZ)(Lngm~)+$9+g06A8}?qE^0!$RS{bO7A^7lhG!tyu7Od% z_KCE~c{$II9&}XmF9bK|D;RPVQQ?(1Y=n&@WU8NWk15iE;1s(j=V$Ij*s(#f7sHZ& z?aTeeOw|(Q=FpN^Uhkn}^!u*x}J z@)~*aoV2s9bqOp$?yKmp(t?<#LnQt=8>el^U&< zk8J(CH^JsWM$P57EqOK4QfwVYXbjzdTsBWPW}Fw?Ukrac+@>*c4v9kOE!PSwLGE7KOI_+FL{mTC`+s)SNcQRgB>e&qfMNP+H!X=0pgHAbR01yVD5{ zj6(@+p9n%DTBI$|>g5i;Udm;39|)v*?dPbs_-WPMKp46vK}M|P8_e#qr5}}vTa7-s zWzf)Cvkg|YL@iM$<#0Dy#-qjvt#`JxJ>BN%YI2$K57}77^N}=hMhpGk_uNxt6aLD; zI)3xiak#o)qL$W-ZsLLSO0u4UH4Dy@;*3+R9A-0IoG&gbm0YGQa9R$Ve|4U#i7?;Q zW&CbO)^5{aGH(>TQr_YdyiO^rT+_9*{6h4{>O&wAn=9?I->oA(e@!<&QRtF__k9@x|fKGYsqOjxWE3 zZr(^B_CX5oiAN!Wc*9{LiWQ}6s;CwK73f?~BR3U^a{VNfDD#{5r)zNcejq0& zZZ+K0^H?a9AzK#?oDd40yXJlQ0X9c*pVaAdpad~!1KlvL)g>E3n`%&br@9O(4_J~? ztK}UroDAi4ibh3g=LBqc>3|1+?5xW9*>*I5KS@1U* z7RO#V$@N+rnA5USv49Zmp$i}!gdB)s{jTnwz-5?lDoXET6+O0R>5OGAwS+shPE5GH z84xVOzR~!+iREhtexgu%mS;l{FNx?i;!+d3-rQ7}8MidSjKgTBC4h5kfoY&!>Yts_ z6~Eu%zNUi^O$B~(qiD9M&ZulBatw+q>u-SSHMzq+e)(f?R@@~u^C>7n6}NK34AXsb zJs56bLnUXQh4glq*QfPCxz0w+K@_LCpQ%ALIbz`Dm4~@?sc2ROWk!qA!Rjpy=>h9I z=!I%zjI;v##a)`dPLt7xuA*O)cRWbu$O`UC0ayqr&yQ$$u(}G_X!)A=MN}OHmx{7} zO>)GW`|MH<7P3ze2O*iLk`W?Z*5|%S1>hFPs$i7FH*1=nb6rK1DSn=k3EpXlGma{a zU^tEU;-W|e7*Uy`tbLZNVZfIIdz&Pp1tv|yF#~iU(usJDp>{PT1bkA#>enu2q5dZjtFN&{P6Tr$M~3O(+fhoA>j2Z3I%0tEK+aHWsYk zNwN5!sa?MYzdUtPYXV=q8X{}o0oSG#PfqO2)mih1Ur8`P+C)-U`iL1)Kx zctZ1Q6Tg=}KK?&JzW)pn|F`~GW`y~7G&fP_TW#-z&S|vG^G~qqVR&r^!M4K;LKIO1 zX+N72L6~E@S8WI*1dOqhsyfRh%s*^r%72_*<+mPpy*ts0GDq;Her)=)P z`~OLF{(<+B2yNx`-Hb0Wg;iOH9H+@Z{Zk0(puh`6*8RvrRmER z`S$zPo_kKp#k}{0x?378UI*2jbHpmm%xKrmRSCR|@bP;lQdc)ej6wxpF}w#zQ;k>A zVPjvoiL*-Br}<`R^rCxh|Jwlw&Oq`&wCxo}MnNbuKLRtyM#tkiI=2jA3s05#6&^0= zmc3?%`YKUc_~@A=*iYzm-zj#Dv5c1YH!0pcK6z${i)y=f$6s~M7?`TRotQpjAdgQ!8%NemL> zZ{INwU=1!)&qDSYE44*K(5AnOJqrd>EzpyfyCGU2+E3TEIg5j4d*oJkpWwTfx}FPt z+}!=CSsdSmQRm}Ls(eQUj86N`YbxU2aTFd^A z*2B^lf~ts8nc{USfuea5)&UJ+D@h9=38blx;+W!}y70z$!v zFO;yw{-qBe4&h61g00X%4j+-5bj2SP5SPPD$jN@wExeNnGSs^4{6_V2>`Dd4$HQ|4Ck_q zYEt#(=)|!WxfOMPtUMsF8pCD^E--00!)y8SLi=3-67wFn@OA)QEZ3O}!9SggTC7N$ zq?sT~i=t`+j5>RRJoRrq)5A1G@hBLd{-i073#i)f-Kb1H6JGy3olGM43+pE+e6s7C|>KjV^xkDhJ zmMy?KVKS$8Sl`89Dt1Ll=R;mcw!FO1RImjJKD@lSkz`|f?gi_hPK#Yf0>I4Hq(kb| z=;iXSw?R0hq0sovQL3_KfAT0KCC6Mm?FYf>-zU2k{RY!SZ4yMbh0@7A+b_ly3t-e)w=G!m%}D1k{8&VY{%GxY-Oe=rWvM(rIzhY ziM+uXhWD^;@CS{+CyWegTY>|EM9a&*KUjw92kGFp#VuquvTAq4wB0j}KfNp3_I?Di zvBCcn-yX&+s6X=ID#;W64kO0&EqdTZWb2|3InD+!bK!oZgQ_NTFsYIfm0~{yzk6ID z^oYLlK=Oaoz0(0lWu4LT4jrh%e|$`&{6EqP1j zIzlu(ir|+yTy}lK0}(ONmt@W-_EO0XUdDVebVifgiFds`XN)0nZ!4#6h|qlX(2}xY zg6Am(FfH5{Wdu^MfTbt0Q$u}v_kFhICU3t>BN#9e=P_x7p#Azg6VhbxaELw~G#Q3n ziVfBZgUAEy$sDS}=wNhsxg0=;AWO_NUj87I117`5B&c!eyYjSl5y#rzu$ywAwmTIc`vGg+&{SJfsPnYU)@|yl3+u^3 z?)Q+l!NMaY3%_wi#d*B`j{w}5c)T$;Jr%$Ex z407Gb^(^TkwZv8*5g|hHD@>jL_N3UA;N2I5;k8PW=QB&FC6tw2Km9XbKx~{9jqtm# zop2akCDs&Wy`m%t|G12~Pg4zOGqk#N{3C~~lYpMh@r089ctQm(Vt171J7+$*BXMXo zS%h4ZWfQ~oqHPT7TnO^nyze&OJQ#F&*Nj$|r-{?=y}0twhc-I-%qSSa&c1)$8dEso z5&?U6n9gkd=>oXkUR|onS zSVAuVlfsYnM{~{~0ww8u7@@wmp%jkK@e8NeyzB2NMWDbQ552{cq|oPTyql0TZ797n z=w`@ah3??eA{JJivr9)&P7>;+fuP>O!Z7cUGJwwFoHV-I0zp&{_Sx7Vokea#YDEnA z-)6Yy@tzZ7lIYw)d;dOA55blC*VQ5zp(2+fh?WefN5FmAiDwGS3*ZtfF_8Z0rVWuijO z+c1g+U;ddU?SLJKu=X;jdrG1X)7_s~wT*1`1j(ga###=f_mH6weHcrGrW47%6RB9c zWhW$-0O_1zr_ye4}Xj(WMa1%>W~dQpN_%8X4BXF~4s zf|g^HWjJCJt;zv%60)HI1_m;cRds*^^z(pX`Uh@M_j$iyDDmxC3oP!HO~XpmsCBe~ zZjr4zT^NR(o1*QnE1FZgf&NSJe=KGgy!i`RM1s@~Mx_~73e(BB&>ZU$csQdnZuhD)cCvSR4VP33nHJZQv^xAFbJii=BmgSPlhqDc|< zxtTWfFxl*l8gT^AS(jr~PVYP*F(J~mDw~|R(YOYD4T5&pz&edFh>u9B@jOAS`KtiW z9GlOFVo3iG+T{a>4T;Zc^|78Fw`tx;V%4Y~9@#{-gBDbAcQ28sy%b2KUzp$zH6`&= zc{s0s659B?P8#(0J&@S=Ib&g1em%<6;4jM0zq+I~BA~>Yx9)l2AdGpg%iQPR!n0a< zMYGB0oj7f(Ovtv-0)wBaE;)eCj|L-wWM+RmpG_|xW8y4f*$T6%oPxSjBfy4Eu!Oe) zupJfl(#tDLO1wEJ^BMYrtanf+wGs(=38l{DR*wdCN<7}NSF6TBk1I`(ipUp+=ipb( zn&!{0f9BhrS8bNvX{vYQM3}xo?c1z&vX7s-4=OZqGq+20% z?E}IP(FBy=K4G9I=SM}v5JozYO{wDUK(oc0q_x}#_zl6uBK?C0K zpMLT-o)xenX??d;<4|5|+6o*GOYu|zUaGY#)y}@JSl7tKjU7)%lm&y~`$qPN31$90JA9|!Z3zF1Zb_?OP=Z9s%?G1!*k=r(lD~DB+4l@$?ACrP*4>fOH za7{7*d0<3f!_`}4|H}rF0seK!^GZ#?UBmASWMVF8?Y6Ew6<2E6Zkt~}FRty6r)PF* zn8Ot+&|`Uru?Z8ptcMSbmSWSZk}4!~MAAXA zVE@3VqnOFH#7 zA@v350n2ddT3?kE{+QeZC(uDlDdhoG;c!R_>?bH+N-M{LWXyv`YL5*&*b&s#h6nzB| z!Fu{FBAOZ|!ooFF${dP@>u&^Bj|c<_ikrEb8x)gVWk@ScZ0s69|xw|>G@%-Kk_ac_vX2e=-NlNax+8QN&Q-wZD$L$= zenBtnBJNfU;k}EqT0$1`3n8v}+>J7jo2I=0) z45hjMPw44Tk)oB=r7@Gmh+oI{l~;}=0LoywZl zTiy%w&e4|@oWIQ!L-5-_D4&P1tilO^9zx&bm66p~1*wRu^2F^6BFfz;@yOD~Pu9T_JK9Y_tdXTzUPA8Oa zuPgZmP0ioF;_)||!nsJbYivSFDBUZr`YmTyt4s@b;Ik|H6E3h+f8|#R);^hTj8EV( zOU}FAVxTjO(Gx|uRqW?JtDIb5AI%`%kkgb5agmE$CG;ydpaUnM`+HcK@nk#4AB4XO zYs0YE&PDBuoyT)D{TT<_ocI&f;u`hB+?jnzk@(ac^O~5h(C=qP$G_^$-&>N>Nw5t} zwRX|bCQU<2_OYV}lk8D2S)v%saecAa(FFr&cgT6C!a}p^ALme{+Uy9$6q>3oM%_`1 zxWoMug@ob8CdnNZd@qOzdFG2JJ932bxy?Oq6nW{gFqP;R={$}m*)anz!_0Z^RSw+ zWA1PWENGCfj6(Mr3iXyGtf}?RQqvz|*!5mKFQSLq;usi=s?TbZ!b!&86zCt=Y3s3Y z27qK7N%-Kd{*o8lXU*||PoHK5d;5@{bEn&F zy+?+q3mb5Uq989fn4V%?Jv>7&H^NNGUEx?GD3?<_10*lLznUUFXbyjwzV#}(R2sKQ zT|87DZ}cDo*;0uQ0X^5g4!`_?`%8r%+N(?YgD#Y- zA}5)ADE%pf+T6CvTFxl>cWbSy2`UvWHR#p>v+vOj%EY0wDL=ne6Uga!pjF`RaN59T zC~~vr`4t!e^gE2p3UZK|FUr6jD<-s*#D6*^zp;U1dkOqqj-|h@?gcKqIMb$B9N}XE zk`VwDprlgimv#UF8&2UToJC61g}jy-r6W>0)shKy=MSJy`MpsGbxyPiCKk) z5#+fnV@efLC)9l7XoNXvSxs00>JFrPSx&7ju%&apS;YHuB~_fm#4q^x+4_}i-P|)> zKK8np{xOIs!~_1NSfDGZoENMf?IQSVDyRKyiZUtC%n=!a1ART$)l>RWcy2-9r)mIk zr9>x>9_Jq;s=m!@WqmL77T0cLuVrs#Zw~lyq7nl?B`RSd*5r%&B)Lk>_~fIQvPh8N z(zlDuBssQxsw}_x1!RP|7~Dc{tGF|pNW-Jv&bhcDcp&9GsdAXZivoO2CgJY|^-p?P zGZo?^lEUE{5tToF^?3=Y9Q>I-LZ?5@@d0Z{xxTh~v_hue;|0lUv%kzLO@u;O|HG>Y|=N*MrAiX2}5do3E3Ya53KF{*?PZSAStv@ zU7!L#(Vc`Zxq&}Xk;mijkq$TKMxSHZ;`T1t!}+2DV&Bmxz^j$A6evz_@lLshMlSz} z%?kA1thPt4Du_1ar``3iVuf5y^d)zAX#*2w{sKLBKYtpy^~iMju_4H5H+vFK7!Y1M zdC1Je+n~)F2EGGX-(CacSi3FlweA4CyBiJAB}wlR9wxH|6svM zfZ(nn6WkqwyUxXe6Ch{^?hu?Hfe_rCxwyL%AXo@w0t_B3IKhME&-cCm+w*qMzTKVE zb6W15Th-Ooed>1qsz%*|60L<#!%#O)62rw|Cs7cw_PpH1L6rKWgmOqy@FK;0elRe0 z0Is06W`XA5MP3@U07vasCQugV4KgoOyKk%bsOw2zEkcLv| zI7t9y-FQ{y%t;K0Si=U|1my^r&^9MX7)oWn{(%vp#I_M>`KbsBsN5UAPoIN2#prOA zWTJm**mxr5RgDyU9P#Gn^BQNt>`HM$J6jh-JzK!;*i&>Qv{a2YtN77c2BW2=1u?ND zaTNA?`T8i0qwbT_DrAzVT?T*n6y6r|m!L`d&RtDKqMzQ0W$(aa#-Oq;7S&6`nDR^A z0x;(_r|zP)p05u0>r@MtT-vJUp%mz+1By9Dfyexja89cJpUUtDyB^v=&L%hFi@5SL zU{>#{q}E4Wz>6DyYrYvKdvH2#Ug;}59^uK~{GB`Qmgte&X|0ul6NKX?U$AX63#K8t5hU>VpejM0@5KgMr5ih!7Rpbs3p+PDWbgjR46!a^z_w; zs%r9FDsR8FYBE)S!rBY4VVVh&`tk!H2mDTGhrLhF3*f++k9}8W2o5Ey5RYz%!J65Z z-LbdU#Re>nNe}H*qU?6qJbf(Sw2)_bsm^67Ze<^UZ_kVstDb=)kqgDX780!D7zuTq z-ujilu%veh5LPR(ZV-y){w8Cg3Pu~8m3LGr_W07F&xBwPQSdIYGtZ&t@_!Q-i+u~k zznyvM{M;k1G7@$nY_`&0n$Ph0D#U(lJ;Huqyd9=H*kY~;OXd<$Z5+>K>6Ox|jBwl! z6ljLccbCyh6t%H}Be_|{zCF*^6d5wRr67tyg;(jae#a^Haf=uTdg~KOgu3TFwGZVm zGffW7l>wQym#~5KVx#8VWH4^1?7J}3GI9nMgvXiO`WmiKt-Z$YmAlirDw<+b0QwID z;0rYi2VVA7;g@M2*bN)i)HZm)EsAM^&$#o6k z!M#E00l>4 z-8OKwMv9H|GPs1BD;{tzNq&o&zyQ50@wY&dw#xgRZVSdxP#)E>>3E6K?I7H+= zjtV=V3Z-^fiOsmM;+cu^AVdp~H=%{RA%pzcAj3l;Up2(*`8PyWPsu;F>oK=o#R8R% zQ(?JPPziU}Q>*91p~7+CJmaXyWBPfF5jz-A@CgeAXPw3K`|mlBRD7E3&G(z$ zg}c?;%UN_bGgXAd=Hh*PAqR`!-$is9ft(#s_iVZv_w7E$h8h59l<$1L%T)mA+Uc45 zLv73K2iJz?%D}8RkV5EH2j35Y`YOnavFbd34nQ%@`cWWFw?`lhf8xwT6$bduHM0|Z z{sawnVeOLQ!wEKlWK~pW1BrQ4@W2&330exHq_p8MGb6PAzj#hNDyLcHWtWPoe1bo!#LM3ctgV~FQPQq$AfJNKte2or3#8fjDSz=SfI8(8VCMPo z%47RqP8!GzD)3>)7tDT8NNpQM2?@OPcQX<*ewecl!gj?)Ugymsw-gYMclFm7BS6sA=r!m$kv*bL{`#_7P?6lceqVI-NrM&tz!? zW>w1EPcBTea8IPY`93poYmxGc#D?99n2BcSYFWHM+n29;bQFWZ_s&$l(NWV{{KH>T zE|%+~h@MZ_Gj$0ZJ)`tfN`5Ey^P=5V5I~qSej{?sgK~(nZ2s1MgF+eZf}?b#2oi)B z(F-v%GoEaczuG!TX$W9dc_s@xaC~1^S<~8%d@>&q1!fy#K%BT~F&>QIXeT#mMxsrM z%S^mYX|ZHyuqsS1QEI6(KdBugK4Z>A6>J_i{06GX5~1=m=b2~5nc#ixFkW~%_GXzm z>^E;$lYbiXw6`If-ZYpk-x%Xpt|A%Epwy0PzTXRCw&B6O&_W2`u` zIqjl{=wv7xbBxLafjKsDXhk*S66zy)9rYWo0a)%>Vd;mv73}n|P98d!*^?rp;fEqv&^Uh070}kl@{`>jC}zM;7Y^QMv_Emh2!67B zDXG_&n%7}uoi@*;b@0A3$6Mqs+kR^;I-0`b<085zMG@GWMh( zpJf`&tu&Au=ru>l72awP2mThky)!F+EK%WV3>dj5=(n^8YRpEh9GhT;L{$zaMbRQo#KjP@tg2KWTect1o0dXp2&7LSw~iPkU?o2>$vZIP z&jTN_Z23x%|79G=`^vNc3=GfuVT-k~gtobYR8?3b@;rU`FyGR7U=-g5v!~H^cj?V$ zMAeSprk}Y-av9DF2H$g7Xa6hle&FzEzjQ{c6tsa(+{->C>p*_}yT*Jw$b*@yiT_888XHOchr~P?-6G^Vr7Gm;0P`%sZyo-{5UM zPA35y8XRio(*ky0Nw$FVj2)M4-dCcFQr>GK*17&u^R%+I?gZopsXfu@sIugAwxo{7 zq*bc)BryR=sct39{ldeC1OK6tSaVL{V0-hUl|YPG*OgCd_{MNQ*iy>R1!33mSa{HQIj1tqT0xMnxt2?%cu>*Q@PM zDIfEpIL4)O^xS{&|EXzwFj9Jw@OWuFw z!uZQX7Kjl|>9}M@^2lZ8`y3)DPZDS!DI28M!<>qC z3@zYS)%O9Z@R@V;kJ5_@iY*1hlZHPlJFy&wg~u0z;h+AH|2y0G-Bg>Zi=={FXXMs^XhULRe$6}W+kMY{ z9||5%>v)!c6KsifnWEJ_6moRG&*si_vAGiE(}FrbJ3H`xS$SiKkC?e9KO0w(_b{2i zOVXBLcR=FeF31?gV1F!QWodm3IQ(cxC@Q66RQLm7?X;oXW?VfjGgbSJ>5ZOPC9X0; z?;kHNe|~t|ElY|}Oe||lZLiYYQJ;z^IyxGl`=l zowPIRWnFV)`-`#mF?`#(N(Li^#GB6x9vFU{(67r1(WfY<`J4MO-})VC65S_wB;F@@L#U1Q4+se^LXLl>LdUjEA^EfPzk!4_L{A=T>#7Ge9ij4?LNnI$;3}! zsv@~A{8&Q61*exP1y8+`YmwTw=cwW_S%`OOS6%t(7}I+-UATC8YyH`k^4DYdkV5YK zz#PN%K|$_^jw{THX1x%kwOrONnL5O!{fQk3Twc(5$ogG=8hpD^+fd|f6%ESDt*1+z z)fbHOQc`c;zxf^XXq6JUH1M|$;qz5E0aQ(co6jhmOLgvjFOQXem`4qBj(HG+uNebT zx?bF+V)9Dm8;$%9vwLKhAiwR(!jDnSdly%xK+6rN1uXl13bFGvc(LgEXZC>>9Y)Sl z_&yDaHwEjrFQGBz$oNf#Tn(YDpQ`D4JVRXkw!ta12Jm|(o75DoUH@Vd*Vs@58ENui zXXMU}n2h9#qr~~wOG^}1gB1LBu)2JRk$CcfOaYE9Rw+j#qHKgIS{P&~a+b+e7`6pe z{g`fv-~CqCNPCd@4-H`NEsqU)27+lu_yo8ma~Al1x9+^PD>I^;5hk-@bkDUrs{@QaI|Q>3nQr83YG1CMtVkq92yEwS6+oY;g(`)zt86`sR*@@b2cOX)F6?0dj|Zdh z-?|t6VB7w+HXF+9Pt;A$U~O-++pHNIY1z1)Dr_GV&IMHOO2ZzP5C5Ny67qNH87~nd zBXejsQz9>=#>iOEddl&GpAcIJG1Tp?mQL3_8!AwnJTmTCHqkBE@ujM6@uWtK(B7(K z(kUy!iVtM9Y2ez)cZpG87B^z$Z?VYe4*bm*FeT#lFN~e6oO#Mh4fs_`WFD#ohs^j0 z&By|`Y8JFYRMz7k%C4^NSc6{JQN)P7j+106(JLaI;~lpiP*bn7H`Io`De6qQZTZd# z`AxvBb#TqNcRyl_-wA_(%vFvRSuGl{>5X>JvG)6$Z7D@M} z>3?>&^aPx_b?yT1S=FPV6Qspo)hSdfj(_-9G(Ue``cKV*GGxM;?k8+P*$>8_pYPs! zV#%HVit4jY4PPXzWpB5Rf7|9ce6Lz^L5B6KAmbbAUDB2$Hc-LakT%09kU3v2c~|l= zkP%i0y=5WWP5ecw(EAZELvB4@eFfxBylue`0$ zddv?PnPgYHrW!mf7BJnnsr)FVw`byCW3Hw|{M z8h&6)&Nt3IVK9*B@ma+0@{!Wd?wdCf%dpYLEhzO(3n!mO~YA}%$$Mva}BvD0-LMU8ECoGuY2j3kL#*)2dEbD$AVBU=whPzg z*acqrHlvsBraCopCYAVdHy}|;K__9;IVH*bK7)F=8hAto@4I0B?_Ib4lcU0aadKF} zqZ}Jr#miVL;C72#E70)lzrpt~!L#VO!7sNo#X)W8eZ_=sAgDY1Xl3~EamU5vD%H+C zT($^@@V_RNkD2A3X6;|Vi~XIFto03#>kdP;mnR(o0g2FGSMA7b&CcD?pbn`{4%UnF zQ%>N+S^L3)C*9yxjhXTA-E(k&(%vhO?pE@)#n5!kvm$@^beU|7a51QuqA&G7+iCMpN#R?`b`mVpY>HPMsnn@rF{XC^@YJkii_k z(Ie*OxUs}z*=~3f9byw`#mA1co^Fi`7cp#VP3K7pxUN6$< zeAUm{Ju?#2gc@=v!(RfWpuXpL{kUV-dVC;)_9yIYq=KNS)g!n>IiES>8+<1jP{5sE zXrR;J^;Bhxc8=S=zXR^mG&i2QvdVS%Rs*Px<*gh4f`!3>mAMc<-{;nJf5_9$gBQL( zNI1;WmWNdt)J8FfIT;G%T`=<1TYqv1h8yyHe)o|ANAyWWbFPJvRy)>EcpoRNQ4;7G z+vLWg*7HlO(@VO%@m=96UjO zVt%Igf?>I##%9{Zj|D+9XokKtbfiHD*O_KfL_`YeBeis3R4CG=S3k-pb=1)vC_EN( z-?@TopUvs_)~HyUsX@zcN(S-nIeBqQ%=lz8z>Ssuz1Yn^?=x}bQJs$u^*hwI-xwol0Pn4Rx^pKW%y&Pm>MjUF6qPuBR z$47o0O#5;WtBD~);3>fDGoR&8xWpv?q-_dCjb zZ>{{RS(mjT#3^?}- z@_Iyj+6DbRTT-{^M`>GUo~F4)LEp=zU`I-veC$&}gYp#nOJ?W7!)!uKB1FsLkU_I> z@8H*gS%gwZt;ItBEOit2d%pzI`5ukIww4)U!UA9PwRN%0m!l5h{;A)eC71PWE1FGR z9Ikfq$(_y4+PbgJb2QgsHtXLpysba#q|chW$6h`{6bB%AM%!WbFw9!ao~OV5Y|_;E z)AUgPfNinZmA`O@ zYugNCvH*m%9q@xJglhPz#e)uF`1lXTFko(LaoayVg1?uILYRcnA<6X3EsWb zJ@DS~DSok=q5^wwvUJS37^K^x45RDI)yxrZ#jS_RHgc`#uQpid1XLN-{57!6DslEQ z74#H1#1A#rbIaTIs!>=twfE6M;&zmkXJf%S>O-_+>$x!B-|T_dWrd7(+kMy4tsxoP zt{yNs#%J)HNEUE^r-7+ltFr%A8h=d~&yqL+Njk&}N}j#ui;u}`u1!m^kKG?kIxT&j zrHfxcr0p+d-#q9?@l?Z{nXj*`D?3oEAeqMts@O<`(5T&b-gTzR0yZn)2VoaRd$Y{ocgeEnV2xh@&LiQp<5e-pM z**+lCY)YYuAc~Ig<5J^S-_;Za&c&?d@T!W8l8ZBz&&~ZwK=oOQQk~PXLPEbmtM55_ z_QRZ|gxII=Seq$#S12mq`*%EIbbM*)myWD!5`2PunmVwYrNMfzu!vv!mU-ure>EBYh?*xDJna^DK-z)B2NpgkRd}-XfJhEg10AB-~!Y zW*0>mxuI}vdFTqBU9ui!mE{^B%~O(LhOASO`%oY?7k;+Xtzx#IF{t4=J^moe!eqF4 zN)C}Rp{+h8sqR1r(In1oECykJ!c^(haBvVqze}^A{d~ALD=C{I>Ouhc`(Dvm0wL7> zj<>rez}69DnLQ7wTLWInqrKUO6emyb%M)uI#8rbP-sm`2paeO&SpX0hvNULa&mXR6 z;W!k5T~UzjBqh}b$2Q|U9O(~UA-W{wheQUehaDP+rvZ6&xbjX&9h@k{{ra0T)*)6M}V z?~qeYz!t%S;Y;Ok4TYu0d<0?3O7lrhjk5#P3_jimz@Ft;#Hx3y*wpCG-rZF!djvVv zdnIDi?(DKU72~YT56@--YZV-Th@|?l1Y2~a60zsKAA&@0jA2+ms%Y1b{|Cs;m*3^vq#%7Di~d{0@veRlYx?o=zH%N|V~c^{zvXLEam64<>%|G)WD|8= zD-ZoaOK{w$r}QJLpc}hRIdB87W>0GZ(j2@r2pYugyzpjLP0pTu8qL#HcW$$QqJJam zgfF_W@Uc!y zEegcM!Zn^o>D{$RBgI&rj@+C}Z{4Anhy^>utKo&$IBmEqJc;17(;if4`VBLy8-^e;bzbdsyLvddpnu-1qUghWg1&jSv^&ax+1G7-ar)u~pr_tKF`dD1S zOAqEp-s!P5)#BoQhVCy8jBNDvUB5yVs2?WrxkRW)WI?F|GR;gM`-uYNW*>{z9iqeD zsyXeBm{l@os}FzOL#WV}Q#W2oi_r+Yb{&NiqghC1b8(ztyx}BYD9%UnZjqUcG{m{t zeMLyVjW7Py>CU6$*qqoj8y=NL+az6Oke{$W)?4v!h@;+e$7&FQh$=P{CsmQ`!>ARA2n16-*FKxRKkDM(NI6CE>gj?1 zi0XAvajJOsTEhJ8o9uIb6Z&LQO2yB%g`GVif zZIw{IcxVn=wsZykrlGMrPPy6kdoQZ)QdU~5$DQ79!xc^)&3d#s{05SAJY>SPU;h;` z@cw1P_QU@S8oGxv^|@G+ep$gtAq{2E>BX&}xX*s|PtasS@X($=l4FCR9rUf-#qiO! z1Y_=MaZmU6%Bz|-e$9CNg}w^;%H*BxBYmd^&QE+wSIAdR?`#u17B!yzOVGprR4g@g zgS3yGP3z?LjyltPgh2YG9~FJmzKto5Ua#d|vuF)fe{G}tu*Tt~ey7>2=Mx=?9>M<$ zBqDcF)Ki-ZZ%ugO^)W@3X$ONhBLSu;a{_}>o)$;#s6ZGMzf3*>?ari3T;zUUD7kx5 z73Kw(u#J0LP=$}1_G!%|l`HF!e*_uPhl_v|F6>eCdp~Tod(Z3twV=d~@Wa^%xTUO) z;#k^?FS#s*;{W=CoZ!kTbj0UQF~u%HZl95IjBvf#`vG_UiBnplDF|sVF*IjyBvNaP znGCkai8mGp%Dju^mLJuT-2Xzk^c^%{AaS(Bw@D!#YGs$|4O-hnXyYIYA0h+5?DzA?|*vnUom|+TQgzSE`gckyghaliJ_ndv|+ z(&W%3SA}34cU{Zq1#xkWWLBnqaTLjTdAOx>(A0OK@Pvsc1@-U)SDvsmgtK$@cE~2pJPt!!0ZM~wteXLk#yKRe^W58 zI-#2#iaFFwXS0B)N~#Q{ES?W%CfZ-iaP$givoM@20E(36Q#lh{u6-M^V68;+OcbTY z;qH-^fTH}{9g>v3Ox$S21i(3TFVzOSEy_BIAW)txrfdkHT1 z5aa@*sk^O0$SB(wGxo;?S0Mv_9dSe?J;K0mnL8apM4o|cfz0?GlimH3c@Qvh zR6SjfcbjP>Xjlg_M3lO?j?O1rRMI+~B_qPMOv?{^VQ9=is_2@WT7dK6PY?9Xprv*} z#4}{C4*0<7ZReEVc_RP**2eY2nqL(vJ@#M#(e@ce%mFbL)T*hj{lJW{wUl&5nR>b&KyIu!L$Lv+;WXX zw$d%|brv*2Uf^sOCPYummc##zs`MSt_>=75w%|9?nDxU&4BmzU8^&j<;7Gj97ufS3 z8GX38$Hx9uzP($ZDBx7To(+vSrIMa+-0%Cv2#_yorH2a+xRTv8=^Qx+-@o%uaFxP; zXu3-H^V6?86)R^zIsGC%tHZ-KhCcb^W1o*o0G$kawupMIaa&p<(>3?yk*>;@g6EKI z@cey%7%M6y`0b<3We=y1*8^xw-HvzQ6_esW{hl35a76y;481yAZABSuL5~&Udf}ZT z)dF!@SXSnvZZd$&+y{vLkCY}N1eeK}b4!AT{pJF|gbi&F#xPQ$AMRgoN^(5z3$Q%_ z%INIdwmY_f)P{_Z(zM*(8=O7YAC@4p%`pImcQ5_8M5RDNA zZ`FA6yXxY~~ysCoA{cGwWyXjRy*q5)?%C3#2gOPA5Al%fU_3P=5} z*mw|&D5%x7)k7Jr(_v~H*@M>O%+ew33-nk38xl5iSZ0^ehEO`t69^(`8XZejz~D1j zX1o2Ia}o??9xgiW)acm0od7l0F0O(7u0o&H@E8pQUlidaK#!IgfE9K6e|*n=S7=g| zB2%KP+&AK3Z_j)y-_p6O$d|UcurL7h&BCzP`57%3rM?WVs-U##`<$E>Ui^j^E})a$ zH-8-r*9<$xLF@AwDo)I#CK02n$z#&BI*|*rs@uCz^2oxsxmg=(X9mdHg;&r^J;^L< zxNmb~r!XU6-kHA?tsTRdSf~}LzoR}46G->-h5lgOp^3E5Nx5p6)Q%=KUDxn%VlDgxEeRDfF zWqfhGW>h`Gis_Kea9qsp8S?w`=zXC2PO``C75zm?{ekgQqGe|bp5%Za%Swi z9o3b_moic9g-Fc$RrM}+f3enq(t>>G*U*q~2er!UMB)!rINQF_GHmEsj-pr^*;&5h z>mvNB+X?w5VIQFk55O2Aek>B@DQ0t|N`j7kW;b{!ubix7KOwY|xNO_GTEcZG;dS_{ zZ(kqiT;V=Z2W{Ew9Z&Aq6lkM;lsz(4#!8*5Z*q7GVKMHpFcfEj@&^ylJ_uNUc}V$3 z39vm7Fn;szs|bfXTS(9hYe)3PTDZ9cnFRmdLX>Cw`(>6!%iV{Nxc8N!rM$e)lO zCi$OXzq1AmwPZoaw6{k_!!t8$_+u`C@^pf3D$Qg|sVmP;`Kc|1<*LVFkuc3ysnxdy z1SdHQsI}9sx{YG+=KO|X*l9E5ZQ!%+ND;Ha0VIv7V7MK~+CN+dmG_kHG~ z2OwtBf8CI@0=YriDo4HS;|4O5>k^^CSFmw`@(C40r2sJ;wM;|6k;D*QK%xLbRIu|i zS4U47p1G%W;bnT4qv!b>#8Fb|6FmE2>_n~|3qrhVDn|6kW{6uCrqefEqtE0Gp`-u= z5s^th^&)dr#nHK#iGdx2j70D1RYuinahBS`IJw9PabF}uBEB`-N63CLwz>q%>56%_dGMt4{v4|lI$ycUv00ozMr*{2rUgoaxxk+5)u+}WhFUn5|V3B z5|Zl<|J(%Lf!NuLk&rwkQI>nH>z%QIx#2&$&)BguF#h<3!gsv2dn`VYmxJ`i?KYCP zy60pMKiqnl^W)vUt17j5?p|JA6e1rkI&h6=PF_>d7_z`$>qPJAuT!3fjiBlFW@NUr zcW7v6L^tX%sytWPRxT!!nzWu3xF`t;OZ|hHXGBD|iO)#q51UE9)t=NJX@{Hd--ml< zEnoe&2|o2M>ULM1bY@diI7o%c({fh6?E2-AxvWXwqm1b$Zvw`$ppoz2#v|lxu0(v z?f88f--;ER3Bg$ocRc;ZZ}pplgY@xnEeXjH8OT5BScYw|Cu0aE38J24T6Vq{d6d5= z4DxN>YwnEL-I+B%FQq(K6Q(M4OaQyF?-ABx7^Sm1yPaK`+!W>@#?{ri^t6___kyJo^Ap6Rgw5gNP@$xq>ERu zow1CqA@oO2ZKUPEQ|;%Comp5ft4E)2y*^y1UpgBT?v0;r@G!YarAw8>j;polTNp0a zz2bIp5`D5{Dk+OO#e~yiFgBawt^=_W{4u1!-sJ@AoUcywIx5jidZae(pIn9THVZy- z1{W5>L`Bpf$C?>oY#=Wv``3Q6WYewFWf#K$q>0&+ zK}18-@N=cB`#y&+N@tSFkeHH3j~KVMA!$F0rT;tTM)jUSL27X*NU)W0I*oSzr@K45>b#AbS&#v1c=FrIv4+`K zWQ?nrCa|P=e%*sEny1n;Gpuwnx&OFZ704gyI_2*Zrmd~2pG7$D#Fqnv9)*O zNwaI?ovbF)#YytmSjKX4-vknpxV$W9I+hy(g;58T$HeCK?A=ymXPiRK-Hm5$Zq@?L z#pXvAS$EQFxsAM#^cf47h{fx{J%%YO1z+@;^DdpUNdKA zi%0d14Fhjk1GM_U=1}T>M|>H^OLuY6C$%LI?hZ53MigrD+)%+K1kfHf201OeyY96z zfSG^I?(hUu+M=7-p_qCai65%;ijSnDJRKX~N@iy?c?-{kCrIm&P3$^}a-^{OOQKQs zOgl5l9R#a*3uh00T+c%Kw4&XEJ_{#i)x`vcS&f)o>)B$EIZaa6)-ZLBT$!2xp_onk zxsLIZ?T)Kx_UlJI$zRO+EHbFOvtFBbnJZ_N8mSBiN$Ojohd#oox7O#gWs{qRhUf|_ zDeDD#!s`W83nS(8tInU9wLBz_{GxNMbM{l7$1;$uOYOknx-~X#WrmV;uPM!c?gFu{s;j~u; zF6<*ga-M!K3Iy|G_nh>V#SJ()SrImg4_dmG#`E79H7$L1Pj4DMz4ZXHTav(NgjM0O znO(KU2Z-87Hwk@6uHRD59fL^GbaAP3rJf8#r%|0V=1BMm_AJJDE94V_8{h9-IG5Z>Z&p}r-yDYn0fWmDtH2L=;abf}zl98}AV!nk zE;SC?)SS?DXhz#vz9b3l3?`sR+ivcyO@|rgDlB+Byfa?W2j?y?( z7F|f??GG4|SS4ar4))H6*`5!Y79FW%b{mitkY(?zdm0)J4`^osHfZ%Cg*nej%2mPI zc^Vi^L9!wjb-XSISoIL_C~ITaT=25vbq-g=f|k-wE3F}>6wMs5i99R+%)v!r+}GIP z-|l=iHz&-NIMOri{|zk>c;Dtp+T!yjEs4jWC7V~BQ)~jBYZ>5J)Y;ZKmlC(mf0i#2 z6X$!pAe>s~+bD+P;d&r4z?H-vbxM$X<3niVh{1jTX!zRI>dx%4C=9CNsQJ|nx`=Ri z^{Ci*+(YE0Bi$;hDA*lptR@gBG*%h6cm*dzmVC$dH1F+d@Un>InBA)22hWV!sY)MK z;`~k+FZsO&%yIthw5iUv^!)HF_~V(TuO@o&g!^AQa>%bCrAFis1xdeu(?+I&1@H9)j?;hmt{v|`_A1fQ`my;HiXhYE57lc7 z)2*j{y&qwhPj?v3efxr>(V>;0-j`?8pTypTU#p>T`ypw>@U5m#cZ*E~{15uH1{pay?gKx%HD6eJ41q{S|OSy0_z7>Rg zC!3`|6#1x&b!sfctD?-Hx=xpml0oPov*r1XSvn?Hj&c99_LUm~*!_dyJcsvP;2BM6 zd!0AO(HZG;>u>8!U)vhD#MK9#{?Y6Dsh9JutgU&tFxeto%Km&%@@-|Jq?q*=>`M`b zh|)wyX?O8SPYZ#CuJ)KX=uhv{Zb#R%c6D3rvbbV7+wrLjJBhB@larM#^vmIGr?a<% zB)jvyNr=_)8^sASC3}G^ogrUlqPe=a(ht*Lpj?K72s1g+!*Dy7krzz&Ex2y-VK^ne zGGEh*C)`--V5bpl$*O-}TPo(RLT0JNzRC4S7_FC$#Eyy)Ei+D>&@|eynaF24V|cLT z0xRrmWXd{JdR-UoBE<%q;b@Vb8RmUHD5U-I1;a#r)`MtDUF^vCTrXL%i|vE7U0F9p zC5-<{;%WJ(TvPIT4jvU;>`RIn0bKnu*k!ktjm5_`u*CnQHct)DoGUTrsmpuv{oG)g zL7I6=LowU``Oj!$U#F_u!=u8DR)<|~+5%o|BcFd({rq8uaTR!fer#Cl#?HW~Gh`}| zZ*aTA^xAICMuPAy4dvC0)O_3e;AQ7QxTZ+*kg;C1FL~ZUQvE>f3!HK687>IjGn%QG z_pW`EppWGQi#2EK-tOfAxtB7-#m|}nrN-a%w(Qk+6Xi@!`Kp`lJ)UPl4i}`mdaYND zFwzPrzIgQB zxa|h&-1tU;v0l<_kIIPp$4hxywAnAZ^T+H_tq(6|QMQHwoG(F<3K9~GLd+~|FCWj( zR+kC-m?1fKYZyNHYwv+^Vc#_Kzq09&M?v`5WzxKTg z^%pBBQtHM%PS*iz=sxeOQ;c%TGvj;!mcfMteY~*lCNpwdXv$O0GPQOpuV5ghJeOtH#3QLGuuu7zGnXakzYF)_nqdM0`S9QJ^qo>R^W&DSQ ze3W9YL}+S$Uz6uPc-W{U&`+~dM2smt^ZcEYgirra+`H6q*cWUdd=}R|$iYPqLYfM| zGZ+R@8Sq16eTb$tjLKzX)40%vt4;j4flyd#l>&7@^tG)$b8c zH7Mpa6j92;6R){S&53)qRO4+0OnPA7v02TGKYewmGVDT_STxeFO?|F3g^O?vYgm{X zO#k7yG)*ueH+`ZXYa_3r0CzuP`7!^-gc(0cD_}vRD6H2g`KUjo-+$Yy#fCoPTRMPj&B27p^qCTBex)Cm!yz zxxD$Y1HV36E&LoZQV|~UWLE41$-@vE!`>{zAjfamQm44wu!H$|??gs2^`D&&-i;Q(zisX4C7(yC9(PnL?tgF+ z&BZFf;_OW8ID0bM>4T*0lk7z?RJc|+jMc)@z)6#aHW4*G*H4A)Bc(|AS^EcW4 zDjn^l%u_tU%6$KAF>#enio9z0eCKaI@4%@g!IiZ6exO4imz>CpW1?Km*W)8OBHSAN zw)g@ivn(~Uj}}u7x^qbs?(#?7KD(06b@yj0|hosS4+&DR!gw5>=h7yP1iZR7K~9ZlkvGfLzyoPmZLOz?q>J=xG;{ih+r`GjMoes9invuq4ZYsdRWZ8RCrDx6P=~fj zvjvo!($OO(Qbx_gsjy~(e=A}6yw+?@HNVMd2~yo?RorsWW-kDG<4GsA^kAb9Hnk}- z7;RcV!fgm!d(_X0?52q|U;M6ft1j-6<8TB8ELhc07bUpqKqGhJQasfsP zvL(*V*oS#K^2j-6gfWKuN<2BOU%#3ANeZjYGaH|t`>ofnktR*{^xW6ovbOjd=3UuhuizU^df}5{oM8VDrCdpv@$oyKf2~)7i$-QY)A17#d?Q(^ z{O9jp*-Q4;M~;aDHf18zpGZh3rz&pq^QAsc>fc5ReTa$1rRjku+je~p{_gI8lo!oE znTKLkK7BKC`IC@uk56K`4Q13r?h^RlN|{uKsA@?Ci6PeCH{V&cY@s{&C{f6#sPF08 zp6l!@%i`cmFUl+L372#|Kr9A2b(%>rgulo<+DJ=1{TrgVsWNZfJeu)jL^1IGPE>l_ zx(n}1IafI~#Nz(KVF6i!Zqvg3cB-|_SzOQ5ZPD(*f~0(T;&w!6)k%ehu`o=D!DzC) zbo6M25A9SJvEn4OINjHN^A;c9#87P}bKdz28(7l|dyk_N_PyjD<3ESY*?D$xk*~WK zUHqjA&qng&hMmNoo~0Wkb_7SJMN}rnSdB&0oBQPDES`Q;tIBsLAyFzyq1nV3HA%Tf zR6}SJ4_Cw{1$7thg>6+IHjeURb=tbAw@%rv(IoQ!MwPu6whgu;SPqxDE)uAb+|$pQ zM5jCI*zF-Am>~OyJ@(0ogT+5k-OTLts_)!65@dW0IxYEGqH=9|y*V;5qiP#DQKwm+ z0l92ZtM#PrQbGvTB2S-a@mYrq(EeYa5s*1M3x5ynK_?qxOKz{jwp(QZ+^j)n;qhcs zyQ17;;aRx95#4RhY?M=uzRclu)7bqJO{JL6+i3qX?H{KrLK>q?@iAwM`JFEeC7woe z6SjRwoibkf>t`{F0OVy`SkMo`$KotpV%;wH@!eTYfO;%@n%I)5?QNy?1AdgCyvW0h zhPgnol)vtxw6xqaZLZ-+w0j1wtd$U~VZBGv#lU~9a&moiNqmU5`&ou7P3&n0m}hu1 zUD;*o*OEP9D5Y(=APQQ`WAbXoQGX&tf0MJR#^84GptHC3hB(O_(?M5QfHgu!bLC#6 ze|~Ft&2?+??G>@z+D#;%^=Z;$S!f{J$=pCFc-l6YwJ{XMlB!lLTQ6&^pdPWZus?dJ zlaJOEoSs>Bx|{8x&86IIFCSxj)@h5#*U*bh4PB-Oc*BmPeM8U=ZLQU0dq9liU1w0w zK2F|EId_;}(;)L+c)y${c>u;%`@SB)cR9dP7SlBh57{g-tlyYpDvOmyUt<6PJ_h$y z83R|icc}hwhRBILxHH<8klASK>(li&#)A%YzC2wN_j!G%ZJ{&OLnffg+FQ#jnJuaJ z$#zQ9C_*JT)*1Dsv-<7S11~`{pLsgOc5~VCSgvgxcIquHdyXsZ?||l|Ty~n2Df?J) zSg!AO)g7Wu{ev^#V62Jtnj1y*IF-*G^&VYz#z-kND+~` zq|T*{F(bj3cxM@!fDa^~EtbqTyhBHIQvUm(sxEQ|l*O zwK=AWW&>#7?DZ|E3m##lP_p+c-c>B8@bi;vi@5cjb07y0Z>HF{2+mqDZ4TLB9Bi9z zk~+v$(;^a*18D z8?7nz40}=yiTi>veVDDOmheor))!`El}gmNAs!UBBjzx?h`A(1?7q)wXv9TVYScV+ z^pC4zi=()Ko^5j;HAXi#Nk%CifY5>ani)~WmI;e>qZ|1qRz&>vJE|0(S26w*IxQ3~{lO#i*c&}HU10ioD%#b@wQ;YdET>Ci(=5<#pFBHvtyANj z-IbGNC(N=;08n3CSgGu1D0Q)c+>8m>fNs6P?WEKEof>kbh;n`DcBYQVU29mwHftZTP;`iF8=+lXnTWz3B(Mglv zuvm#UA&h8KK=8_+8z;u!iTU;wi<=A8+K#(+rW<9!^w`>QGdrgWbuNO4{VMm#yeGI4 z=*{J10<~G|**XtrxMsLB4{=GzNt}t?%1g4Kxx;Ebe)}+qmsO}#5f~6n#hH4x3|8Q_ z%UO<3ub-*2S&3Zg`{QMv`uqGwiNxl{rHPGc5)yB2HOq3|;*{&|q)oFA9T8{Mg9EG1 zwUMUm!iSB>`b|v1dym1z?SU;%vXY2w2W?hJ@)9#7^>O(||LgrNlmzRZf)15_Z}6_M znAC&wpG6a~BbFC)4A$CgnX>iveVs0F@s$bgfw}&&T*72XXw3diF6z$rPLvfQKLb|~ zV_xcN*oV$wG-L5x3Tvs05$r*j!R>0sM$fOk3_v&pF!tW;=p;e7SK@cuv)-3)$^H7P z{63+!*jYEz%HF@%-i(SsIKDIBNM_FUp*jSt&=ONah(^IcN4k}w>EA=&kWgh9-+8j| z#X1W$!A5lJzL{U`*O50)vv(6(EO6m`S14b<84$g{9ua830s%Ok{ziw_X~uVB#6&4m z366MVGtfQ0G{thXOm1sj5SJMJ*rX7-7mVRyUhO zz{hrszuakS(jyGzR;wow7Xc-N-bHtY<>FXhFTY~p{glewd-P*NmP0#E-%g%Oq2J3zRrViIkDf^XK^3Y3nRXU}H``AO}YC*+M7au{= zSk(9n+fCjH*M-tWb%?^`b!w4jzN+8zQ;xUH$}Ie0;|Nfh`R%09V*h-tgFA@#+X(_z zBj#O6ywPH}^api{6B^G+zi*yGuN5*w438`Qm{ZNgk)=|u#$obCcc1^Z>-Y$oH+stn7T#?Str9k0zf)Y{ zu}TlHY|>rI%j}C|!xeU4`D(|d1u*9awMhmu!4XV~ij4uhr-|nl-R#jXTZ}xpEphh9 zD6HSi#+cXLHu0JbUzg2@fl~1mWEw>-Kal{x$m@qtsZ(zocarap%TL`^nw#S%>@Gw{ z1dPwiIxB~I1tq|(O9h<2nbbO^lVKP2Bv_X|$0Izq_%&-NG5xvV;w>#f)r~RcLe?YS zBC!Igj)5-Rh=EF2piIvU`3ZPAB_p$$yA9~XakSY}T8fMpINgqHytI#bSg$e9m4NUF z2QQgby(V}^XbI)s7$-)EjywuxMYCf~$CgIhBRn+LUG1=cqoTj|5}16QVmj{K zlsR9Q0X_(+&t`4TzT;$~YTY!d(tED3^8AygPFeqksDz{R;)t=dcCU z*I{wAXnZ^*DBA|AOLNcoI(0I|)TodkS>gAiX1Zqgk~=hw=0;_~dAjWP{#UN|w|TTJnU&vM05 zWWPTz;BYh?4j5K0E{%f*rKeHE-q~w#a?X}%osIIv_z6Rw>VQ5nXC)Qd!WdU z=rAcmi*Hv*L@0e#$?g!RDrUUY4l?WCox`V^#0~~VsPs1zWtL%;XL{0%bS*c(vNNFs zwhwO*ekX2s+m&ZkK3;y@VA7O_xphdS;eGW0TV$;AKeYhzuHEr1n=GNVu|lUVkq+N_ z9tSUWE!MYF=PO22YD=0ZQ0d>zYUWND+ei#d_)sKUaFE0&G0K01+oWNXP3@u4>ScI$g`${0V?=NUS zGk91z+rev=v?LL$gj?m3^Q;$H=zTIiald!kY2ez8o`-Sw9ihr?SH;v=eNKi12@})R z0=wg4Vka7+m0$Y80hDJD6uC>}(fJv7I{Gs?u|L(wX{Lb()MsLGURM$~bf*4dganV- zc~dKKY!$0OP#M|oCc5P=%jsK0EhU#9X20ny)P zyJ!L{Xz+9X3mB^&ezCt$VSE$ZZ*Zj^Qw zVNp_8)9QYyFQ4sfWE94W!KW-9nEzK4;r#d}2^3vXQ_hKEI?lcF|&j zk6q=vEU0*z1zFQn{mlUdMIM&E@)z1BBe%SL{ zo_k3kaLIGESheX*-y6Gzhu&fmGc~K`L2-b>`Mi1q=aDZCQQ{j_jHXETCNUTElXdHVcOZh?t@n{ zA4pov?>v~>q(*HG4da@bnQ>x-V;nUz#dtbm=;GtzXu%?8#$BNDA9;j*VHq_3Px=@< zVPgW(6B_ksaSdg^u(id0<62Z_^x(Y-q!-*2$-udKby)TM^ae}5vuj7qe*MYeM!YJ7 zSG7B_#kz5IIFCHYj5I+IP-T%zJ&TL0f?#eV0pO#ti(L?qtkaBp(|`Tr`v+Rl8P8ms z$n%IL>LFhu!m39pSuGVKJ-_|)jX>b(OXUPM*b$M~vx8M+aa-ml$Q?2)EG@C3;Wv85 z`EywnW9YQY-~9lpdsIC)CYgL(m%wv#C18Gwhg6=meUoe+cIYJIYP&S8(xho*M=a!x z;$78)Qlq86#X4Y)H#b+u>nrm#)BCRv-Sk*jjsXrp?zgf&wP3RyD-B)jPf!H2Ychm0 z|7#)qo)-B&Ez*{sXt2ud%@9#sxw|pT zN4)*uMeNWo8r_P>(PEt`|K^WFA5tZ4bA+5HjMva5HZ6x+r$mI$i0^LNd0-&IcZqYN z-Vd_pcjiH*#s_NVWDF8A6e*ki_@|Wgx2RKR#zbYF`PZ<5#x24U7ajaxBX&sJUgZ1g zn#Deiu+>xzy_3xqeIApV#7OF3%aMY8g!c~RM7>2}NGL`K?8D_At7ClocK>r&Hzliz>dpeKRsVGTaDhkqN6pC!dq{7Z zw4UoyH&<$<<$cE4Z5_YD{15Ju#RS5R=Xrro%#0JJiNm1GG})pGbOxwl2jj=WqI#Udh96UErN4msH9v7At9!>TP);-ML58PaivCXoyQ&}OKbb< zF^cO1!NP&8`dapDm;C|%LydaLsaNye0fSH$ahjeZ{QdFcsZoo6J#Yg4*B&SRo0K#( zcFE8PKG=djRQGM*lY05U3y+WoJo?(faI+*w6A@L6?>?(ryPBtr+2twk*<43SC?#=L z=k2Mk5Px=4X!#b&Nn~1saD~Eg!0LQv!EQmGb=ANayQ<5tJf)+)^oDc1u4Pp9jazhv zq;PM;`{Becf<9f#rL=Zj`zTVHX2=7QjHdRx0uQonB@L- zu;4hiS5kqeb)_Jrd5sf>v(alyB;iwoPLsC_hjCR=B8N`y1E-T7qp)oQj6+78CP^$@q6~cCeth>ev6yCbY%p(l}%g(2ok~<;T`@n+5pP!xdNNhDR=c^=v(}eBW zPUlG2|BX67%jLcHK$n@Z6|seStdDh7SaeXD>Q$RIdGq%V4DFO{H6LbK_9Ux^-FdP= z5X8XW<|?FaL$Q48XgHrvftpKWCh&}VVxt{D}=s|q@+Z#7-q;{7HO5y0m z-Q${kcGI$h4l!N=pXOc_o7NNPW931$euwzwonu4HBMi=Gce$%rr*JVJVh(;LADO~C z(CoV}khD_de#fQKy03R9nb*wt=AFmyXs+Z8JFeAaf?6|64B*`-TS(`cd_kF7=UH^kVSnsio^006 zs^y~x1_u0t27kO3a9`09jL~b&3*$fYTKF5GU82v^u?x(Nee&9n3hX8bqtOvVuYS0E zO5E+R1qnIS+K#k;Zw(+WL0CQ3Mg@HLK8m@o#98*G36J44v!%_ztg39;0SBq8ch7b@ z7}L+X4>wqyBviy|4g;nJ{Z z>dimj9tGlI?-rcytuMMSIE`uF7_Vj#`(znVeQ+@91UVInjnHMK4Xrc5z6NQCLqG zw#ErNUGup(m~vL{R7)3uk*+wm5DUc0fSVcPSNinOv?A(M6VM@;8!yPn8A!T#m;1f)6 zeMiu`UkQ8$n7_kE8kviL2+NbMVzOFRQm>H5#B z)7J@0J?d>EITj|FT!nyT62gRH1yu>bH*Txt57(zVzk2og()#7%?3YH#ilMK*TwR`B zLzOg2YBV0G{2e#1{?JCI^FH8swUC}kZ*|AcYaX~6(%{ZBO}3mpG=Z=R%1$B>ZIJIMXGxk*8Pz($O3kZP zXoP*`2#QTRTlw#0?k0Wy{C)VRMYvzfQ z-7wyudy4%-Ry1a*2H1b0D-EXgu1>W%IQfq1_B^ehvIzIp;g<%H)ltq7lo1BK6|#kH z-X7;I9xYYth~c;mwL`O#pT68GkZZ%`#^vvR8-o0REo*(pb^cFi?pZJ9kU{r4%Ftng zQu-sY-o{TQZL}EMoLOx@);ah4Yu>AOKX`)I*s}wkwM9K(y%er2IY*_=G$60t>JK?T zRZ0TJUJk~^-4m47ZCq%;nyUK`irw0*GiBclgJHgdg3k6o%2c*DO5Xuu(K`3lNT1K3 zw7SEIpvOiq)wd?uz`z;UQU$DBQ|a}&av~-iM=)x2r1!H2oW!prcsio+6=QNLlV*B0 zrKqyXEVU00l43Sd_+R>+Bl&JDIT9WOi9Lr=+)63ZD;-5`$UYD$ekCymjUua%D}7UP z0;dvaQ(*5JKGZ-#^|p?8#z`%7Enb|%cdV!9kr!dHI@~&lI->9It7z%ni?dqY22UR~ zm4|%KsJoNmAt2w^2NKO!V4HVn_F9O?tN7S-IE0%xU?mYwK@Uco2gq~YNP@_Q-d1Wo z_E^GYhqaB9W5T2XM0JehKWB29P7kVQ`Q&DE5NHNBF~(t5YNw_lI7i?jkK8a$$~xXJxD9bggX zNkg(*4-<`rpHZgu5z8RRt2wDmw1v6|8X9pd$7HI1bDz@eF6RTw+;=J}U**VOg8k-VxL`MMxnisZp-6{MQV1{sgHYy8B zR@G4#aK+F-(Z$K^MemVXrWN{wx_O>z^UIMZpFB451H2(Yc;ojcV=grfGCamr zFF@;lvNkuyx^gps4eEApzcQ~sugRk0t{_!~pjo#fdN9CH>uvOFEv*~Gy%9dEMR=># z)PW-b-?$Z(osE3JL%HJpXPn<+DO%J#Dfk9iw}lxaBnmgsHJflAZ>0+9{+?RNsybF0 zv&n7R^vYT--LAbM`MJI<*`vsf?7)?|*R~@K`KERL%Eq-0R>r31CWyZwQ;t(L-3Fi_ zEFyu%oxyR+*mbd=)p61z4v?SSd&N4IJ?+r~&gUO?_M?f2gCP6QKqSlNe6YnXhFFS& z_#vOI3d(0M92dTq=}Z+Y%(tyv)^1SqNfp^=^x5r0t07NgGQ}Gt5B{zuSR;xX0BwY# z5oWOn>y+uGX<^sMc$!qApJ0<6s8HiP%OOKS%b70Xn8=^oA#S|oJ`9bCtx2Mn@KUOL z$dm7qz=n9=dXq@#;j^3%mM5S?NQaDvBr%F-xjTQNnk^4{pJ*4W=&kNg?^>%I2C->^ z#VT#OK-i1qU(e(}1ZaNDZMBE*$M3BUcjY=xM#aKozdw3~h7UxK~89-lBDtMQD+0ayixv2eBNBo-O!G;lA zQH?EHW4KTq=e_;=+O0*{m9u<*t+-RMWxk!L6~37~+uN(>a*v4k@U5k@!x=9J+;IMF zwxY38GZUJzk}X2c*P9eT)IHES?n0GshvHoJgYN~Xo8!;Gr)P(9tJC=I0r_5Miad>wHl=6ZiS^-jHmed=L?L)~JQB z8gObE+1zm&u2N=BJsJr4I8gtDhI5vJo~$iIRwpw^>PtUB5zfXX~_lxG&|JmAI)y) zMc5OM*WrDOvJJhF{Z~sXi3h7AioW}6ON5u1PYj(K9HRA=Rg<}GIV&!sXGsNi#^Fu> zqxocGcP?O%2W5Mu-#-Q{g#VD?tw1?a_CoOxh6W5bH;w z(!+K1fR$Qt|EtpXpjdflnpgW`V+7HMW;BX2itCgzzG@8*Vx;xILiJ4;A6`d!AD?WI zvi)d2Sfd5Xg4f1i%wIyUS+$RHuobm0?@b5_*o>(a>y^|n=c)XC`6X-MAkl29wg+$K zXBrF*%g6aOuOOBhs@GG0tSKLYG$o0nBQYdJRZDDc1--7HX3swkjFDN4#z6xwEE127 zj=Q-6Kpv!D8t%ew>Pb0q6`42ENLyqegJ>X*dz&Ybqd|E;A8;5xpFEJlbjUCtALtZQrlDOF1O_=oZRTK0X9MRIoTG0bLfK)um z)?2!B=Z?^CIX_)i5ps9&he8#cP?}P_v^_^8>w76U4a3pLdXIKR~^C8zPF|$!bRqkCZ=bNxQ zY$@xT@8z|k3oj)UJ1?k4PNWn><;Yw(kdb^F!rP$x9y8JGR%>g^Wi07SigaHU5ICH@ zG1LM_p1w61Jk<`Tc!#b?iTI5c^*y9;v~Bz}?_agmcyg^6)xW=vR&C$ABCrOT9||n{ z?Gig;__cw2O}U>=tk2;upk~20qiIx8c6#cEt6}_i{vKK~zIo%^UC@`Fr?x5pX4TnK zz6CXaTLrI;@l4?#>mF`QzCZVHdQq3~pR+@*+B~y2qK0V$VrJ4kHhPODAOCSltHi$F zLWPP_-=nmox~lh#`{m1VT?-)e)$14(pud1-D^?>SPbgjsXZ6cfmHVG;it;->WjRVy z;(opF`spZ7b^>8pkLyTGai1>G7%Qc8=CGc>q*PX? zM@W{`+S<{Q*;nS9Cuv6EoYH0HjUUciI~R0)Jd(v0nm`Q?q&`bD(pA8(tZw;BB^-ML zi`#6Zr$Mf2)svib?bh8+K&ewXW>=>{u^^8V(&8e!xG|NrulKZ*`U^_T0wH`LUci$H zV`V%{OK+ZJN%>8_qquJX?0S{?N9U@|9vx0Qu_-YU(!)ogvA15jtc{+zZ8Ipv3!I+n zJ_o%$&l2j&#eJ+>Ke3Z>n`*R)HF`>%a&AekaWw88Ef&oC^zO$k6PG0MBqZ@#pm=xh zr{t0QI4Sis3HYiN?5E%ShrNgdKve<}-pR-S!{mv22m6}ktA_7AfXAb3ng!IafSxhN z$zK*4W&-=W=G{Hso;Twx^lROF9FQRjGeH*tBaLv+&BPzhy&vdF&512pc0(miXz39Wu`b*l@l|&$6RQpZ8qv z6T$jZ{|N-^@+>9mmg)SR?<;9Qtiu`0_F4ss1(eBwb*LgaRNPdxgJ!L??sz{*jh@)Jss$9I zPf=E_#X8{>3wL7>fkih96{6EGSJx5+?Uesf-MB^p$c3$z6Os06U8-l9NTiVoCx^%C zq`Ff`NT=dg=})P$r`^@|!-a>c2-hV5Vd<9{+9qRDA5}QPmWD&OJqntdv9krk`Ri2H z3nk7-m(2ng)pPYM0V9^+#5r5C0CBB=rm~@%>7{5{(#sV zu6rF|JDHQ8r!vnK^@s-?oi5Tn=eQi z#pzS(#%?9*L#AeAQ<@qt&hh$Xor zd&TMMQ3xs43f-TnUFc+1@4MLmuu=8?Oc|Tx@QS9r;V1#Gel?$+HgiHJb2MwY7L%C& zQMp={xIDtL{~2tuCi>94+J07J`CLL#;Y?f>2)x)(P~G?h_JPhkWhynuj3)9_d`xD~ zm?`k0HFmMhd?1zeQ<{i9YnMN`DSQOs9`9Q=PEp=GmDYu3Kh=+)Th4I4F=2WsO#RVOVX5vRduJw>;F6vJf_%DPF9PA zaPlC(A2S9M&`49V!c71cd@%2PnaqKEpA0nS+0~bvOaYbFV?Mw z?gbXtUVq53;EkdabL(E@7_sb(gIf;$kr%M(cj!tGgt%`W*X{Y@eY(;sj@ zk(T#^34js%b=FE&LL*R3`w38GeKfh3(C|(8-Be)#xLKn$P0PMul!jB@PhGC!hKC;k zy-wP2EXb92mEsz_JkL1vh_{iF?hoxlU|TA;&+^GPiNF|ZVd?r>ml8d>loa*SeB*y= z0Z2*tne-r!Mz`$$L4^g9mx#Xyhnd(L$(EGxCFx3X|NB+?&$kw6by=U4sw58D-7vu6 zk^N?VxnVl8oD6LLK|XMbTj%JB{wEJ~lBnGa)*lP+|6{CpaM90Q4W`7;k>OAN&1Tm1 z{PXiyCcoojplc+*{%?L!Kl|2_>zxZCJMG3Lg=EkT@J0TuzJaIwHv_97^6&L|SB`IA zKKXy+hXMZg+2#NJ8Gs)rzq)21#pR1{(u9UZ;z%$xL_3k^y>Ou)4bLxleF0L z5rD^k{`~2>IVn7~RU#p1-TQ)RABcUEfQ(%v1Ohqp9FD&9_cP6Y`2g&>gxOP@AXy(j zzuDP;e{jJs@&}D3KvSD6w9J})tNUV~X6XBI>6bn)*3L(?;{Q$zs%q4Fn3T&x2%r??jt{r^R)_PW_AS@P%`q|6vjC3}w$NBdmEZ_zz+jUA zK$>#W;Cx9x>o58xw*Jz9`?I9%p{bX76P!60!gt0VUAF0phoQaC_R)RB$_z0#1!*8P zFoLQB!e(CFE3Qo-Cnf-o7x%DpI|se^`;va4?K$^cyw^5yCV_tj??XNTEzVy<#DA`Z_14$j{J z5Wm-uP5fkakAnd`Da!)T(kIV@&QEz`PXIZs_GTc8uVv+>4X~2lN5J-c-5MVFZA@#d z&c$M9f8WDFPG)8ONRRxX_%)cs@$My7p3^T-dm@;nDbs2HSr<)lnl)Gk!zy>M9qC$+?%jKL zH7SfPpt(+0!lMz`GfBI+0o4dfR<&`|Q>6FK2e-g1KfIWtA?jUml4IsSoWLAt*E*T) z2H@=HW5Viyph!bjR#xo=8i${#?6@vQ9{x6#i+3+$-S3$fewyv2d6W0sF*t}1;1mfE zP~b#}G`Tg*xLTm2GT_8>x31KvGA-R|wj}^yD9Dsoh3^exeSpOf@F7^bNxMrr>C$|L zy;#R$EzAwz^*5DZ_;ooW8jb4vvh3GKNQ;j5RU@;aL_ zDa;4sMP5nsnKkE&g7ZVi!PFP;gNd1!?1FT!A*g|Z#yyiAIjleuzys6_aRM%*HR=Zq zg{bq4&}-Y7rvF3Sdj>TXz5SvnilTxA8=;9xk*YvIIttQzCv>HUCJ=f6MNyNcLp6wby!{U)vrQdUsF$+6@-xh!bvZ z92E&e_V~)Ja2|i7qs(6+*)xm&(z(WtbKCn*zr+(BE67 z4fth$P<#C2_XA^ZQ*<)Ky+AeZ-gD6nFnSZ7qskt$7v!A&ZMjLGIs={vU`)rEEIQYi zG+(58y6dga*Z{EQ1%AYerp7DW^L28Him|xApr1)xWKZ6aXZL_~6|gxOShM27(IHfz zD0WJ6W6xTK5>{%-B!N9}0_kGb1`i+#&Rf$GB{kT>CJBj_r77901G z)e*p~2&Zt?`#@55PYSg>wCX((=O9=waZoT1a4^G3G!&iZL)!g?G?YF+jqP?chvgAg z`v>2{w!50f?!PY&CxiM6_HSe+cajmxXH6K*;}a2ds~@q?hTPey9?RxU4|9|8Pr9cb zO&_a$9l?M-vL2j4myhS3e-cLaLdEK`wq&FBVplBp=GKh@68OAEEecNOFG*HEfax#z}P?*1=or0B@ATvqC;8PEkJ=H)F6qf-H}D32X57DCe{m zFj{P*pa{@@GhJPS+JUgy-7U6qC$Qz70_!i{l}~d8O6YRbOyRq=%V1{K?U7(EcgB13Pt7{PZA`JWpsrlYKEI2_6(`81q&7 zV;#9^JxW>32u$!~A<;qc zot%kDS~Xb;|63{1b79g=s*}2GQR-div?==gH#Jpp|J;Q3R3$UCEh21`l-Ol$a0>o` z+G>eVxJ8WzY&ur>k}`%J6UvAy%oozuYDcY@@d`DE<>r6O4{%cXx%)3=$hk1zKKWnz zq-eB}uv`8ni&?$SD)dfis@qV#m)o|{Kvz*HOY~Pq)a<8ZOqAQ(WQFyv)li@5YrBDm zr}+2jcSq zxH*t6nbAmp&P2Wz-?wg-bN-@Shpt{U&C3^i{!VijAdZSF;VX*%fuU!^)bfZu4T>jY z*g=oL$UK+hbk{^2wR*B7`lZ&fNH)U((_4-_mOn@CDthD2m3PB(CyREym$1${YIrV` z5LIEov&Hv`@6CJjSM5*qDPn|b3;NpNB|j2b2yfa?Y_bh3?`e+>Wp9Q6x_`*KAcQ)l z7#*~(0O^E=zYMR&A3($m`x z^`ZBEDDwQ3RxMLog^z`LF|$_bMP*wp-t`5{D{YKj-=r?$F(bSb;$|3tkcKV3_zd~# zvPDzS^v1A^M=VU`DqR@rK9|AL9ij3dbgp4MR!i2>7x%9af0P%Ktq_|apOK=kQX5#4 zi8G=TK&R_C+^4V@TZh%=2&H<#*EQ)>){b?Pn+4b?YG8~bb}!3nx~1)+irI42B#X6Y z5#rcCc?wuvmqwR*{lJIY@xS<0f5ZkF+3hwLMltHF05!7f9 zJ8q8~ihvyEZ`yEO4wUrOcM~T1Q?TKW++boCVG5kgJpp?Xl)iWGxN+^B`JkS+RHn&la*eOZ6J#2l<5vE^NpNcqK|k zG4;Nhd2C)2QwmGQ&lK{uta#w0NeT|2V9stPq7{BF389}z2S0Dt)z2;;lwfHXiub^d zSq^^7Bh#gTc_R5FY?=@$oP>;ioL{bh=)O={@#*bBGE&hiSR0&^M;$ahGC*ZAr_dK2 zsb+m^^H)hG=y{8_0Qa8&cJq2gZ~zdg#B;9xK%^>jwQR-dwNQh0QF22i_Ijz&bvxOw z{hP4?C!oHH+ppdAiTe7tXi?4bo2$KdG5$RcYLrZf0UeQqyB73?SK}!4Y98}N3hJZZ zQ;{#e%E!(P+&qP>@!hg|v^s){^cdE|wd6tgtW3~Kke7(yY%-F`(1r@(_ek&8SRf|Q z4BCwYSN4M;VPgdQT9hLH$lI_+ruN%Pgn+Q?+VfZH?Mf@3M98UAZ3a(u+`^_j~g8RkK>Xz@=YMCHL87N#Jc}do-ngk1+38q=OD3f2r>R<#JCUiU8 z$GGTwVIpR+!{ZQA;J%uWhZm}cd6e%B4)4ANGp$a4h<010{iIE(9*gMEK34haz3Gx$ zV_RsF4zH4YIK2Wn7GiNPv zpaM@0vi86~i6zm1XYu)1vko>Vad&i9(Y)F7P-{Y1$j1rPl7r08hUC*-b#QD?8P9dP zez~$YWuL=4Zzqpd=$5?AA?7GIWg7Y*p3xezpEu$pB5zdRd|cL5q|-pn@*otmLpgE( zvV=AOITcW%{QN%(zrKf==VB0&ee(a7KRf=ni28rgx;CAS)?Uwh*|!@ud-K+#s;55# zYxy?hW>eZ$ru5|!_we(l@X8I>RlBjNm4YlK&W()?`;hA&p33@3oGyBpR$PB|U$>*l zM|{!obNm<$1f2CCgpwDGDS;>}{mm?w~9-~mG1&}0W;(!k^JDI|7I?S)Hb2c_fuW%l%?V9ZOiWDXs5heCLTXd-4bp9W<4^xQdHk=_n~S9O`rZRMD(cD1c#&U? zSWOCwx$p}e-^p-(ek87xT-Q`OMK5WkeZ50PMTgWI;f;*xu5IL``nP>sPVU|Q#cZX8 zYOk}7(5;DZN?I`z!J!7shYu42uREXQ#qeCxGPu#lh*yrIwuuhd&JUbevxED zQuXq+4$n&=X8ij=kxc)HH-AO&CdueL--@_j25<#jo;x--JIcDFexW}+CFOk|sRVzY zK*@!wE3fXck|6(9;_75%_MxOK7yi=b&hqvlNjjvvuPjg0kxc}Eo%`KW-xWkH+~&KH zbjdv?OVfE{6-v_4zdW2f|AoOPoKD!axJcv@QtQJ0`L0YtwupT@Q0jizr}nsm1E|yK zV(whqsh!|bN?$+AEQI6>4x^JOu~7K>2sHFTq7!yw<#Ln^Vo94WV@b}lZ6VAqF;J$G zRMC)aXWWIm6tC_%4uXcAR>|}HRz^g$6|&3SZg$#eXHnFR%BdC+&NoGP937?b6nkAK z81*Z)tlS~uo@`B?Jo)B8+VZhSNYu%L5HT6XS`$?s3@7>4+khmRfgY!|#$Ukp*P|k3W2M6xF>p<$#HF1GE@MO)pJSlDdGRYem)yoD^F)_ClEgb|Oy*9TAq#3S{KR7Tm zC>2}xkqZrK%r?^U@R1Ur93Pyoh13?+0dkF!Ea7GJZa$-6VriRLR8QyyiZ^ zhUgiTmD8PdxSFlyosmD@pD7z2bYSMpxipzY=9Ndn_t#2e*s#{MGoIJ-99IAo9y_3; z?sIcj+uo^#;;_X4r20baKuIh^Q=TK7G1GPEP(kM=4PrG=io1pYV59`0zY7 zghIQVVRH^xx$NoDDtEif(J-h7QEIb4-U<2~yURE)0L&=Cm%H)U>EHG?ZzF@K=g3G! ziipQhUC#IrnDxt&>XvGX^vc@!MDf-bEetb&BAk2nL2<`n`-GE6TArjNz)k&?qwRogV;-N9Y~^9M&m^W(Ie)$>8mwvO{Q?kuf8 zQLAiZN*)u4UT^dFOHt%huT9tTPt8M%-<}=^zGaF{TF$Ap zuRQq*IQ^&3G;(^3Q~%|_)SOOxh37}&pOQE3at==;WD}1TR7@E!SR_xy*BQ_sIeE72 zG)!$B+?zCW3DZ^=<&fQLON!agEsEGbGdSA+cHr5a`9!FjP825B`}LOKtq0t*F%I8Z z+IlU+i|%9)J`zOVDon}{OKoIr2GTy91MZ=8!ps1vff5KnM5^H8QvN9*pbPL#PoF)L z6GE&!{qW&K=zI~7rPLXdruRuo;sD12RHw#hP1M_*!AF>3Yxe@<#)h9ie|7*YL&;c! z;%yBr($HTA@JUJ%L0`Xiyr+RSwY9Y+?Aqh=<24Hn^t_SC-s$qu;s64GIOG8c^puOM zZ^sMwdZtM$^70#~(EL}aAW(g*5vcZY*GJ4N+5j>D))if(96_yS%3{zOJm7uWdP;eXzETBX#` z*!m05wT*0gYAk9RxT~)7`mZ2kD?09IHX7IIjg6q5uCHjtlD@Ds+gL!B@-1i<76}u# z@UIpQ=wC*MZ>G50xC;cTh_GMzb0^DQGfsprEAwfpN-Rr5%KVm5Qq}t~y{Ul;ilJQRr#uIK<9m~IpOtS)O6T+Rm=3cx{IUxf52z~5tIo^x>Y9J3n6 zZ1a?2G*J<#PECkKfi*%Ocr)y6UINr;HNPX^ln5`G}lqMvny$ombHgToW93ykLD#lcKv}I4W}T zTY`~hr>={+k#jMx*5|rCapt=lEl#sujh1x{?2CkC{O{potEZ^!kP+D?{Xop|Q{%KeVK64cJm2anrT0zX}m`*Y%RIn`XG23gL-6KSoS9@oblEzK1^ELB#*qd( z*1v{f@&$4(Mh^-ManB2|#oAUbIoL25FZ#CzX@=Hz&alm+K6*`mfB&*NtL@Mzd}uZ;?eGiRxW&>Tg0n`jK6@mdCV!Q{c7HXw*M)p`< z!ZPOcyzLUM;$DkcC5@~6Nf))!9pn0pFNd9lI+~w)Mtx*Aj_pH_pL>QMyD#24{FBqb zW8PxqVR`DQS7)0@gTKg?ejg>VbA&p14Ru`clN^iEhF{#J&W0FlXZ}`5j0fl$Z~HSW zHD;*!a{wisO#(H1eR^ZER%zITqF7tWL`^S@4L;papNYrE{MX^ZiL4*`aVkVn*B{u_Jn&Cf@vbu|{m6 zJsxG64|(QvF!x6Ij@Z-&XLwZino5Pqs@N!U?#Du{v$DlV=_!v_$Z@H8YTZat^bI&p zg3DoAws2`c)(2MlrqIK(?kZ>hH{)<$z3JDLL(G`5pE`-Zg|4u|v&N6Dnuc!WG^@gu zoihkl1?wZ$Sn9%4t5j{eWgViOjk7MM-$G5-pWM1kUngM@mLHzCsu#Y0PwKx;<3w{; z*Q#-5;^>bj&quZy`Uy%hgE`g-DMR;t+SW`rBJ-U)nnrgbBFu^3e{qPj^qcV+du8YZ z1=Z}+*r?(M1y#&Gb%ByAAtue~Gy9D*#N$l4-yi9&%*Wh3tDBLjSbIQzJz^|&99eVE7&%3Yja`_G-eF5FT6uY?Euf>JMLV5*O_IkWg_uvQu~Nk_RhO3A0a@zBzI zG0L|1245iMUASl1256ezuh{z(6fiGLbFT-VwqXD}lDq)kxa|c^(<5aO?3W~BU{B5# zq$H~YWDJcLnX82A?PHyN2|w66c$~)i4+qu!unuUv?&6Lt!&iO#0FpH6dyerw|Ew;+ zU0POnT=&&n4anWAyxP7-s+^U`PEn^~xpi}uL(Dr{bUMUq%EMzDQ!R~xRQgzDr31_g z>^j$Xe^iypI3K$HCj0*L?($%Dp!FV2Y8*$co0&+(lB{i8M{`Refd`u+^l&67cHveI zFYzZ?)c(C^#(jgEyTj)CO26tF9rQh%I<<$zwHDtmhEoo)vWd*z=D+vatbdr0s1}^b zaP%ubh*pI01-T`YNM4<+>R=_+;V}F{>CksX8KKx(b;KeMMw1(+Fn9|^O1BKvYKh`! z#JH!y$VooYuTa2locDfMWiaI>Fse6`Ae&IT(Ui?vQK85J`*S)sNh)CB7OhHB#IJ*=fmbQRhf_r!rS|JPyk1IbO*C@~Q!sN}^|Z*E zrjvQc#L;Ao{&b}?M)Jj$s$WsZ#uFaXdCKa1LsG%x4bf7YeN$`If{!DZyIhGkQ*Mnm zm-z%47B^Pkf5eVtwsF-~#T653-5jXCX?aM;BIU&k4+s&~yb-JNs8!lF5A(So>*U8Z2q!;e=7! z={rALAxDD*@dN8n1;~EKJty<_wyn+{9M8gV=K}VuHm6o(tg-&Ee!88?eD~XWb%W1; zmEOj68)v$6s=@CXl7;yGpT)JgQ6lISd9sv{)oU%}PHu#@p;~LYK=H)K#$3N1g`GOY z$gWJ2+D`JNg&ce7J_roG`n~tdySe6n*UkI(jq$=3eq?@Y z^Q^b`z&|xiVk15bzUARefqc&RSdV^G(XapoDDjO>JhfMeAKvvmIe>uJrD^luRo!^Qy8;AX^h4o|!w#U@14 zU3S0duo>)3Pf|MQbb;}nBe(o72}Y}J`V(ud%#7ome#TE)Y5CiG{EIay+axnRY*Zv* z6M_Wevhy5h3e20Bu;dsCy%=isU4ttmmN3eJEr5Pyno->SAeJ|E4dZ-<#4b0sktj$| zr!P9qUv;*pQomr9JADSDBvBQ)ik7&&92lvy?*Ni z;>8Z-#(jX8{ChiM+@z$gu0FRmT4upF(~?UypS%n=TdPxg3|k0Mu@E42eXzzI!OT-5 z!@HfNN&kxUkuY51%~95$xBqqfCS+AuC@>Hh=l=_Xx-X|=a^7foxcLXlRI5+|wa1c!J>~Nm|c9g8Iq7fB)VeN3qMOQCI1{ zB>KJ0F?RAE1Ts64!c2<)xIzDamDT)zmzew?{KDnG$J_ngKv=>Ah2qw?>3J=JgJ}f% z{+$8(rUNYJLFU3DotCLcW+13{FR}fX>^AibJVDz#hUbW872PY`8-QW}jTWsS^2jCh zw;2GAhN_({1zp#4V+f$ULw)F?j#E+-@9Su$nY3e--vGaGUOoXJZWSnb6936{q&r32Oegc|d zcD&tRDWybysKE7!bF-)ufS9|N1~ccu32klni+6v${bUYE3;ymHQk)+y1vp$_Q9SoP zCZ-;4FIu8rotrA>LWMV;H{N6rGnn!r+8v&I0PS+{6{5toGN%>_fw)G8(bCqs!e)!P zj_(#Q#4b*!n_%plY;F$RrjKrl?u3(<=oliRdlCiu|5XCZWc(p$-Cr6FC+H(ND-oq@ zze*%G>i3P7N6T`_^`^bILr~Ak0ps6xsRSTzi3w9cJ;2pHT{isa0H|%^7rKv9fC|7M zM+F#oA8_-hE5|yI+f~Nfx$(pC9My*liP=D*;xr$v(*;nVKL;3W>JE0bu(q#9ary6!D4Kg4no0b{_on!$(#ruqfx&s?j(yq{BX1YCc7?dOhkKd)PwhG`#wC{$~x z(!tmohmQXA`Exu(JBVx$jFMl+D)3($0M@6Xgz6q09K;PA%*PsA=!KJ&=olllPXC4Z z&edFOJUzk$L!k0vCp#L$pLRQ0Qu$0f?+F$}n%M^h6rUqcBu5=j!s61<>1x&_gaI5% zgJs)|qCD02)T80V99S^f`$hMY$af$j(B~`O)5v|pZ5ZHzdwq)YbxVFI7QNceP4$VW z-KgnStTpS5;MktT!ed8$CLg?d^(vjI4iuxc!`Qo>g-^N{CLu_(LLl>n91g3RIJVZ0-HczF{)4Lx`{3~P`MfyjNn zcF)Q10)+!iAH}GWTcn;XA2Ywel#7Vy85jfV7pidhNS^6J5f)9wtoYoQ0Qms~IP&`& zlS=F9c(w+B3M}l`S)~;MxZzxcG>v6G%t^G50Omk>AX%jTBu{jOK?lcrfMmK6N>rcD z#kSQXj}_tL`<^^~D)soullk9Y7-G)h4v2BkMkF9g;!iN!btik{y%kIRbJDS+MaJUW zDU@_VadyK^nDYC&EsMPUB2R#JE%rVqEN*7S7F=|7tc{k2LScJrHS@XZP+~Cp9m7H| zT9oFcW7<0*3Zbzz&BSy(0H##8d+80F-(EJ%hPndfTI30F|ADm^kWpA9P{4<^f&%0z zqU2jLD8;g#jM;p}F&7;b1+><^B(U1(YQactN-CHDg7%}OMd>f_ZlmfB{sfh}Z5qkR z$-ThFdr+`u|5hbP5(5_alLH)+!vcCILY4NAz&-9Er>Mx+xO$44S@9-iB(e!od9v7t!gwR?@mrep__IZ$Xrq>}ZZg)pjoB^T^w9)CaX zG;XX>i)adTYeRPWXza+@VZX29wq*f!T zYBEK*@1{^%!85By<@J7RiXWMz9H{y3SW6FkYbmKu%fm}R%Z71LeMD!fOH{F0p9RV( zC11sCqy;p8MYeg&MVqK?;VUJtyy~)!B_vpsz#>tb!_D8yZ{|?OJ&o^mMckb{7hCOH z{T-f%TOo4Cu<*pDd{X7*CiSBFy#&1n6uo^ehAz`~(+!jP&XYBWY%rCEK69Z%Od`Tr z?c_zkl2R5{F6dwiK({w+I)xnEb$>tFPSxr01O8yMZd;k$d+hv-bg!a4bjz*2qvnUz zY|Dmyg2&8oo;m0ModTpckW==sR@}FHi!l}O3dv_LKU}{le*CC%$`eCwDwOvf|4H7W zQ6Aaz4ezrujnymF8n@}RPA*T)4G>>nL~RqA{rLD`nKxJc)Qal1zAeXM!g>b32Ox;s zkmRc8E>oVQ5~S!*Sy~VUL9aGz5R~u2pdU6i2r-$w(${OBnUT?R1}1xZk3WGdSwQk< zp*j0w=tADkAQa||*&acxiTzj=;dc1r`yJiAy?7lU7HGHz`o< zVGIIpA#6aS3PAZ!nqXu1r<_;d9=hGFFfqJSX-w<|wL}Kgm=PjC&!6+Q~5Ls@0UNQP5S$pVp_xcH+ zZ@s>La&lr<3z%J!rq-N!^CQ%c$@7h62A(_K0Uw47b8>GlNmtSQN6-DgLmU6!xizNZ zi$g=8Zd4iqH5|}OdL3<$sCIdHcm!6)#)2>nSwRNk6vO=3^)!xWoCKps0++NB<>Zti zqeh%l8fZwO7$HYPJ1l~R$KKt6sYPMy{Go7eztS8&1FsKtj$Wz`ircRQZ(j6w+->gw4Bf(&KcTR;-= zUJq;YS&D#u#@O8K1U#gArS2szwL3$PH-$O#S13r0ji+DtwI#)->B5);$+U zl{M{m0ho3X+X-P|{cpr+-{&fK3K%1wk&;nFw1q&7cXlt3JQDtBL!ES(Qkm0uUg0|T9o4_-Lu*1v6K)d;d0w8(+vgOZ_j zy1%~;-5ZDmK;3P4m{6~Mur|7q>9G{`d zdn3!kcc`3SA0HoQgW4=~eoh)5gh&Bik(j2YN4zSSfUTW)UZ<^}^>nyWhANRtX962Q=KhZdGFgZ~C-QNCppq>X5Q=PpMd_DK;SJ^V3 zL)@{@FftEXaQpY|g*aBbntYhZ&yhjf);wuX^`c@?Iv&cw$EV1qo%d+IE85wBY8RG4;M^v5K19K= z39~hClL?;n!QZ|`0OtDN{(fv)lSKQSa!flA_4jPvW7CWp2*0&mYvi>9%OkW`MZRC~ zT(H61829;p>J>i9sD#4)LRvKo!j`VhpOT^3|<AUyax2)?@e=1RJ#qZK917PR?q#xdnzsZ9Ueg|37Fq0z=S&o^ zivXb>iOe=yXzj>m$pBe*-MF>UdW9HHeKwYNDqR_uuV?9%-B)Ksf7A=}|3aCt97ZS3 zh9vF^{NAYrhDCl5!-9@x&(_;sP|tQU2Sx?I<3lg$kbG<}YzfwAU*D6++rFkj@iSQ% z5mPu>W4^ZfQz{1-$){s3i& zsTke3e0`xiCxoWAWazBYZhY!^vU=IczFhU?>Ee6!GHp)KfL6w@{Qdrf$NER=g8PaO z*Kpl`ywX0BQ(vHSUdLd*>RE~NqHEc-ba0)Bf~mfPjqPNeUX9CY%qGPp5`b#| z>Y*Ms-%Jr*NWc(U+msSy8+}fC4^s!X-hMbdX*xY&E}wdFq)er`TZe~#BWnX|F?rb6 zs864GhfvNBWY+VHZZaz!YbduS^PCY5Z_sueS~V&}ynAy<}8~<@j#e0%p}1F%lBOZO!iI1#fI8vQXZ;^AEO$RTdRf^YXr_ z{aMuqfo7FfzlOrciq)O~g16||00*o}cA+PMNeitBZRXC*`I~h}$oL%b>EKd3{Ad&4 z7eEdnL5(ClY&YBm%8#xDC}tiFFN{tY9CVtQd3AVN>yQl^ydks}yzKZ8fEc;T$=P_I5JbMmZ?aOuUQ8>}`SnTR#f6-%p|@EoVJ5Vt8lISHH2(oP;z z&vm7vBBT1#AGZ(NffmFoDak=E7X#M5>*L`zx7ATClE@EI?t%=QCwCVtepIZFn{9!7 zqefFwnO+xr7mrnZ{tMsrv4UEZ5)NWYfdXKQz~`>=9hXCoiLg>noILe&lQhjjm>#oA zJnI$8wOHnm#JE|IFvkz(tmvkmce&U`8hk;dd^Ee9_v<>4nx>~7q0xKl%p^kEF$#jh z<_DVn7a%#%P|vcz=YC%45E_L^Ap|chKIvOzrc5ZXLqI5@11r^H4jTslcDJJk1wvj3 z5M5|LGWZ@F0V9c(eg3dwDu1s*P!TOMGaG@Job=@Q;{NlxANoC5Eg?Bu`&O2%dsHKM>KG4beEr9;u$RQ>o3vh3cK^0pl9-m!%^n-4G8&=Gq31^Sf<^KcCl z(fdHh#6zkoXTcdv-wraKI{v%~>LGan8BplX%l0$WDl(ERtXi>gE*RP7=HSR&ULS0c zp@Xl@&ax{d@I%v8{L_t`cciC`iF@+n73+#2Sq<6+(iG1&HHA^oLJ-mv4HPc%_`9B` zIv8!GP&&~+Rc-gB-oA~nov3;R3^SJYo_d_mcVHQ-g#uCtYR~#Y^G1 zH{3SIq6a4*aVb--opn#7mBTESj#j6^nB+K5D~V>;?x-Ho6ssg5vC-@n;=E*~Wb6`R zr6DmWmc|}a^c)(JS=eC}8XXmGwc#kdFNa$w_c`^6aAZzz^6IG0;S@coO9~X{++Bsb z)D?mVk;$C3ejC!P83o?>hl}PwPx#MxEyK+Y2U)g9PNtY zu<7^MfB_Gog5H59x1*kA4rtM3gfcw;opQ(EI~nuEz4e7j7%3Y2V2p!Xpk|$l`Ph0- z0~1rA^taqxWZ1_(ON~n zf3(|3N5TpP8S!O80Z( zse&vYVUnTYEOmCQpqu!jZdN%a~T-PTItx1nMr$uGOP@xeOYA; zl+CQ^>5M~hW11v?-CwJ667ywBta{@DC{G5NjT?iB=aR#@C4sEZ;XAe$RIWeS=y+me z^dQvH`m-G7mUgbPVfAv1ufg+QvdZNo0-U<_x3{)D%%&`eZ1H;mK{?@c z0s&%sU-G$VZg^z;t<9^q@3JMogsO`Q!9awB<+Z{cM$&64{TKigcdck)=DILN`~_~tuX(RB*5|CU_BDqLp)nkvv!SV?UON#ZBX>c@T1C12u(k~@e>qMc zJnh?ct~v$UhM}~gZ*4y8uTNUSx~*Pfml|XhWuJ3uxfJI?G1}%L{JB@dKnEU0!FR&h z;xZEiCc9MBD@4v^QYuAk)9gG``ft-a&X3z}SeOpJjtofs+Ywy5*AU67E{1Z*`qq*f@5k&yfByb%-Pkz}qFjriQF)ujmGGh45(uI}cKgppZx8Fi z((I8!eZme>G_l&2PDH-N!N9<_(0RBSU2dJe$2e8%7Pic=C;}-%o!H}GV^{|VvYsL4 z@lTp*R(xOA$7=~mI#?UL6W?#dd`(v7{z}KP5V{&#ziVI-6#B5R;B9%dv}qBd@A%{- z3kh%%RUx{+vPE7s4bAC{7Fknqad8II7y-#$2(bA%@yfrS^xQ2yHeAdkykBR*4DY$D zGys=^?Ij$KVq!Kwe9XWCIORcD<#$k*b*9vNnXN=U%W+h#mo6W5U*AOe&nw3B4F)%0 zhL@bRNiX`-_MZ%Y;3}8EnoNm|R>O0b75Lox^1X>{HcQrH`PFNaW#gY%>15?(>XTo* ztMMo*lmQCP?ANWVWr~IsVx{JXrSqlm{X*Ks<@I%@+qZw`Oh;0_EH_`hf4Chc&c(`M zZ8D<9iEz;`u#W0^ttP*v2NGPr=qbM50P68-;D{Q`E46?sb zmrD_h2@bzMUVd=*K9)RXZ*$1QYMP58%5EGR?SEyj`_G%}N({Udv)hZkyuSTmcu%V` z07~lCxR>au*pW?Syiwp~joC95^<0a~*Q+0+6%X173kZQE(vS=JY4j#wMP_2n{+M#NQs6EkRgvw82-tyGsNmp7S->@9tIv1w z_)Zzbi^2n_v-x>=UUSii{oo^w={Ze-Xou1YK8|Ejiker5l@D1;;Bg#yB-5x>poY5` z82V7yVS_d>EG!n>c?DbBq>)06b`b$hxG6R~L#ZW+fjyI`+L9=yY_XRgZxJ>5`-zNv z3mHZ4G-4)YDFJE@5*`b2?#q#DZB*WoQ5C`V~1_M+^A_Q1I!g7Q@dgF}Vi9q|cz zFBR{sO?KbiKx<=|L7m#^o?>T`mTy=l9mAo=aZYXY(~q2JzF?DI=t;4wP#`?x<1hdd za`-#mmxc_;q~Hx3`bU_qS0FB!)+7`33(t_ zt+SERI}4i*P}jf7n4<%4GQ zlGp&&B>eLBLf2G1u?HbvBpD${`Qa-F8WtUPxotf(_roXs=oEBh3I$`>9;`wwWNFqC z7^T8T?H>KGjSWRU2Z@?`RVEF`Sl`AGj81?47o3P*sxxw?s4>fa(sRMH%~}0JQ0~j3 zdL~2rJ+qY3qWZqtOv7*rpo})o$jqFqdEEM=4M;j=P^M+wXAqF>6`Fu48 zN(pNTM;h09=3o0URy4ZrKa_xf7Re%ib^**aL6^VjJEkEM!XGSR1-S9mDZ?JiD_*;h zOlW+n?;gs)YjQV~#_xW88}NiIdU6iI{dbSoGKym&hbye$DXBgOQxhX)Dclq@e^~qA z4sx-HqVc(Fa59apTM!WQ%68bv{jgdn^+!YHqvjqQqSHDdgK{LjyAMuZn6GdDxg}$5 zc4DsF7(1Q6r+{Z3z5V-p4%vN)&Sz`Yh5aFTwSIP;g2&d@i=eVLw}^7VU;=n4ay=%) zoe90gNims>2Lr!ba-b^nY+B9+;v^(aK!+g`#lL&HFhI!){MW$0rjzwpznjB@K=#p##K@$@z(fD*FaImT^V@uVDw zUV;%GzGm}_*c#1;mM;EWzR11q58fQ9YmjkWBjf46^$R4dT08Ic0OPfNP<)N#V0=6> zrgKS!S#Hv@;hCx~(&^Z{dOrxIet76`6~hm%1WA<8CoK}cvbeJN$(Nz6)wJ5stcK&+ z1FskS(~&Rhv?;wj%wHR#*7^ zl@jut6c~`6z?grLL{S%cJa*i|#)x%!bp8z#N%kE4Mw$_Qw3{wdRt&v}4ERNwqo3sf zta-K+IqY(20;tlvfTsyjEfw>UJJ567G?Z8D+KQZYg4PYX$tj3t({O?OeNo@V)t_tZ0gfCIV&Mbkfh@l0-y z0VFy}sn7~D4ni}s4XTsGFCNW{gQ>z}Z(60h`1X@*xiX784{wF9_6@!MF&iezhO^O( zZ9m`Qv_;+Cj|kV?UPS3}5AyywyfVm2a?|FhWM=h60O zDAZQpxIuxP?VtU1Qurvmr{dE@*m`)f`s0jotXE?2dudcqR;tv#ESf0de- z)%`odIIY@MCZd}sG7dqJEMPRH=~kUB`xGhF(SC2ak$=G{&*c%1-u zQR7kRNTHU#kV_BDr1Dym^FmJyal=<)1L9nHaBwhJbsv^_+G_c3zTWN3xtTwPeUTmD z43QmQJ6;%kODPIVdu0!!kAi9S9Jf`y|WKVLUH=ulJ71aYKig-Tx$ z2}x3fJVu9xUFGi;RnLhpKYww05*aX}S7s6aDlY5BXU%)}A#6a-@cR3L8m!0^sIXN| zY93|!qS3TmUMaP54RMWJPpa-{D_jOJc&<`IIk}bQd>3;TzwN+)?ccw@pUmwnYitc& z=k7odrdgAP+?>{~+Q}p4mTsf8%3?mrNO>M{@%`@W=Z3F;^tIUTO-qx|Cy0FdA|pF5 z9}RRfk`YM}NpMxeGMnhbq>((3;RMuESIia zUi?+3-m(e4HyfHGkMQ2h-`N<}fmL+XGlb#?Hb!e@m{pQkY4An7Zu?mN@;5;Wv`V8c z136%sR4_C91dwxXg|wj$9L!2dRtedZ5RqRy(T0sa$Mt&REa7!aen+AFkL zllnFAJ4%CDjz~!du>LL{_<|xYn={S^XAY9Us|&x_&jwJef+(J6PUm$*D^sj&;{{Tu z3F+v#@VHfpCz1h_P$e%N4t-{@KE%%SSgHw4B}SPgTp_>*9<{%!%C{Rx@LYUXX>#g4 zx=%3T{o&%|RC>&R`rsUf(<7v}1e{|+*Xn$?OYMmKhwB96`M>G@05sL1e(q=z6LYa| zmCt0xq-@&f#ICL!K5i5c_V9O{^p#g7p^{d*aR#2&Hyh4%X*c^|QIXR1_lCRgk zdnmInY=3_Yg3qGBxdr(iZVlzS87~iE^+N@2<-Zeg>!TfZDJxD@T0{U~G*Iw?{PxW2 zKEABJxEC!kj9N0fsnB;dg8gtQLex0}G{h9tQ!VN=!st=jd+WTv$nCsG{ z%=u&YGf!jQPZ>?!Q5BP@SpUWRg_6Fbv;<@mN81UzcKTf)HJl;`PIBTNy!tR_Rp|rK ztVhmcv)*k!doeXKvpv-4c|DYM7@=d#6q&2YU!;^MresfS=iHifn|>)xg;%ZfJu}{F z+-!)ZdcjiKGdt5vx&`D&9p78N{5)rbTxXgtc&y`edK&xqG?9N#y__boI^794c#pA5 zb&a>-&BcqKFss_PATQPXlX+M9eW#K*HiK1U!$CT^R@<47(T^v**OVd0E_WA-8jsaC zYAu6<8O}g34-y96{!pg}1X0JcA76*j`xiBy4jm&~x8~1@J8FRqnKC-?E&|rSLSJO0 zWE)RO&6;=WF!GZrL?w`rzvH(Tz%H49Sv{hN)aZ2PC%^rO|tTH2S6swpS?8e4x!_dC;D zzLeFqz*sn0#kV^Ac{bV^S_#jdt|(m>rF3XGMGI02yKO}IPKipVcpS+&^R~v{S9GY_ zu-Vodd}pFW^bHez{DMWrs5mG0&!4&ISfi+$;s;Gh0-mQ6f=8~02bnjy9@1%s{nIf% z)hVp`;}kD0KHIH*hCA~;>TKrs!;a|F!)f z7GyV=g%%eQJ}eLCbc%u#(qL8!e+M|iSYvN4w`nNsJ~xa5T*Pm6hYK`%VmHNsaxBK# z$icoRMX=>~X)`85sBz@S=j&X$0jI`<=FwJ>#%oS=GshRZ3ON|D>Q!q#{BT*U)p_Bh zzySux)!@T^zZ>G*vP1W36_nw)1ZmN<(x;yMN(R@qW3&VvcGoN7=Sle{R|qgV0UH z>2x=C=PO@ywY5RKtIET5W5-%Xyv3(G=5pDSStgktpp>KR)6iVr^xfL7d8c@Dj-O^b zQ<0%;-`d%Oe^(ExU78&b-ve}VV&zb^n;&!<6+!?|LW_m7$8HL=9L)@ zeduvAdRRhRaD%kZ!a`;pMraKd)MhS6(D=Y+!VFA0g_-ilkvDle4~kLLN#?WoNn+XT z3&7ZHv^e>!w8&xT14!QRvDqJP8~ujax-J#3w=>>%e22y-4klo+$>aUJ=bbH#`opBz z_7?RnA;zv1rt>s0TC86_N+*0f_cq^QgShDnH0Q;RthM7>^fMxAWqO}%bZtD`N#v;H z5-UG1L!~=waz2oNs>iw9+@THsc7-o(06eR(%w!hanKmspws?z_k@Nz6+>*1$|gMB8x<#dsm5o}+#I(~bV^z;L0PoALDNK|GvO z;2F2`F63c@z1=AZcGIVFd?ZRJkyvA^zxbEmaUc7R#_ei>e)Y0A^?1*ok3Bk9XK5@( zn`W4|adMYHJ~3ajTwdGZC>@Dcrt*H}WA#PD&DzAmJ;THbiD*c7zyJ?*#K(K%0^9zH zzq668SLw^rZCzE#9q}e9 zN_#_Cd;CJS6e>9iHe@IvoLIi+JovBjbk>WimxyY$Dgq()bacI zlOZ{RO!9rtP%jKf#++j4H9pSO+OkQ#M-q%@f)cAU#wVDBjt_J;TM;GrXKNV*KLr+Mv#&C!>!M4B@M9kEx}Ir_~pv6Kj9PqfIk& z@-ktywY9~$&PL@ZMj!Ux!<-a8TbOg-ZZ>{ly4fvHa|)z49vij{Jo{xVbzV#&st=5s zn0UG<5J5WJ^+~!rm50JYnPk>6m-!Q`#lNoB1Q$DegUD(6v?`Sv10ll_EqxVcGZIqC zquM;q`d8exyQ5Ps_d9H+6!3^>cC*Z*4CBStl)6Sm3X;0l|XY!*O1dPGs^f^bG{*=X9>rCVm*(9HB4oSLRA0YzGN_sZs z$kSBT_>s7A&~mJ0u5>!X?Ig=r=Xj+yz02|Oqln$^tPWIzIrP5V{$OF|ZL(aa^}cmp zIpw3i#5fwZP;W2!-~qq3BuY^G6|!ACqMktLcFkX5KDC?GH{@D7ZF=kBOJFs_)R8wJ zp?zmCSB{tO-Id*_Dh(S1YvkAav8_at;Bvy0Rs<|<_XY4=-DwEv*W1zS`=LD8cb4hmOmm2XPms#7J%91_of2?ZEOej=SrM6 zq^mFHZ|FARcY@U`0@|LX2jk;+6oGRv9eM{351($Zr@oFi=sMS5^3cd2v3y$+opLf^ zO~X~2010ogbw5F(s3pK2mTT_55nqTtd!&1wmsf)Zq4{ejeY zBA~D~*{rmq90L<@7m$V7r& z|H#I7y*6KN!uIC3ZKN7X&h)Md5>Nij>cima=_xZuOdOTmyHq@w+8ns7$FjtAPmBn2 zuMU8iLl4wo!=<7!3M*{FK1{>FSry$IBKvdt~cYa=0i(JByEHK@=;s0Tb^k1gA*YMO`X z@im@_2Rm~zF6(>hTjkvCd4Aj7KV{DqWjd~&|0bOsB7ZpkCVkIQgx}HO^CCw-fi*-z z>%WTimC|A32`vKA>>}~mKJAR z0XL(wl=ZiK*|xub#twe+N_SVaK;?RJf^N)V(f4Vl8vB zu^n+EcRnfF+>9G8(Bhh^b*_9_{oZW*9oAb4#0$buQp{^!dQTtUHqG1jQp6LR5 z-gq}y+Z*b93)k3#0|MGl;TZ{ZtquqIL)cx5*!t<=KJx?VM%CirYbK+P;dIFom*Sm7 zUHn8j!7q9hu5vj3R@=I%p2p1Pv#nm8XC@N{S2I9ptmjtIv9Ni%$7RRt=}Dtjclkqo za`qYx%CrEs-JSG&AxtcZLGjGCTSRwr9V|P#$~M@ghJC;>P}lOQ3WOemB}@;3zobIw z`5TtcX|ro|t+pm~W5_X~x?O@vs~L*U$YfHRSZR4*=U8HS=YzB!2`e+m^()P_xue^g z5^T6!wm#8Ckjs%z7rRL*8yrYXqGmFXZv6c^p*}zdimP1TueOiwQg{7D0M*%(60&TT^*+z43gs0mP)Ej#K{`F<1-i)^(HZCXuGYj zOt~%6pIo{>A|KcmT+E zYQ69PyU91cR;ms+fpM~E?idAdVvPWk4SD69U9Doi`q*e%@ZISf>`&0hQHw+S{BJtr z`9ygcW!E(P`1SG^*5-X-nO~Aj#~=Ku3!(>$UXS2uOsEkm7ot_$&$ol18)9k|n#bh2 zeq@^A3@Ht9De*LUW$#C7<}! zd^T++*rX2%E+u-{5}1#QWJo1bwb0=%8F6YA^21|0P3f_xrO&81n<(4Pi})H`@meu z^z!>iql|_i@FRV3f!*n?=WVTDHGLLezI_V!_AP&T;0V1ezKejU(kQ?GKDKqt)FMbF z!sfQg3aq|Kt{(rj1>XyDz!K9R4D#bx))of1sVy3heCjT5Pu9z$^EG-#WFEM5(^^eQ z*0$$%9-Nmc6>76s0uJi#q8+tFHR_IYa;<5QjhG;2`!^d0jgp`+KzbW#bEoZi#^QL9 zSh?2VHou}e9>g|B!}hQ;PV=OIVMke39e1`t5HTB=L`HM8$S3S~QjOx+8ikUawjWmi z-Ur5Q@dLt(CmNqqQz8sM>|$+VJ~V{y`tv+&17G1L&!z~S_QkqTys05!6bD=R&L|5! zh4?z0WRig3b(D%WB^YoXcXbfPZfL3lEeAb+lZP5FR|wx#nd5#TZ-|`5GjW3_H+%>6 z78&&26kVLEy*n25B!qPj1>EPGEx{9KA|rDbvpd6I84X%DcFaRh%WSSpcQcP~EE;1^ zw3F#?heVTqZBW6Jd7mJ`$;xVP1WY#!eJq3c1#9m}|7%S1{@^RiG^seDL4*08y5nA7 z<+17XY1>9}7f8>cOm@AFb*z)HoBq-RZAedjxpB(=BO$sF=6+g#?V@atOcjZ#r7R)g zFWEy?U^_At)e%^&0AhXk6~ua^2~i&g;VE=JXB`xM_jyS= z2V+0rkt-g_qImYG<^Jyyb3al_|9i;jlpRY&Ap`BM+gr78?!FG7g<)EnqUrp^;T4yb zv&ZdgMKiAeM7T)qf_gZ(Ni?bdS{c)Qp1?@~CW}*cci>%d50L8VQ8!1J^^;K~0HSA7 z4vwjcokzI0rm4F2xE0f)^s_PUXV0FA0iclC1W4?HtC}qPzx)m_P*I~#Pi;WpU7*(NefWSHq%+7#YZs@r9(JO&mrNMD-G+$N^1F#`r{)|1p z09K60@c{_4wbM2O5B5(uFFt0)c&8wT_vrSBc(lu55E9Y@2Py_Gu8H&) zl|(+b`FY$I;5mAaGY(so&CLdN)^Xl!<_lrV4_WWslL8Y$!FSo)%d0{s6GOz$-L zA?^Rv0{lOmz}=SYnwa3|fU^9N^9OK$bd4ZQ_yp5!?a{P`37~*$oMHcW9}L(3Zax^y z)uEurCF=2a2B+~j1qFZpUz{7ae9neX@Y}}Pj&Mn<1P7nl+g~ixrGNI2r?U-2t}Ib;B)UN}83r^wY=H2QEVy*4k1gi=4bZsp)eRrGGz!xZ;No)xRI|T7zFO>faCfng2UQ z;$N>q+^Re%OZM;Q{-?Zrny&R^h(_gsnBu5e^~pga$SZlsINv7nO8fqJT?Zv6r^zHM z52u$OTvO=N6R&E2Nbl4ZnB^B7Gnfsmp=C=oPd|qedCdy`-K-6o2;y1>yOzsL8I#)h z)Lk;KS(CJ9Q<6W)tLnay?9X1s_+t>SCLu7Qmh?-@o?{5?+wM|0zdS-fQNraH_In+U zQxu=~__QX0Wqq-<|V-;G2j8e^GGOBaB^6GbaA~P&VEwc#o4Vb zAO>|W2~K1FpZ4a*N&E!%h1{hj497j3kq8Y^W|}YKg&Kut2c2xm03!5|3l5A@Zm-Z*-Lo7eKyfpu+{gt+3}%!0+k$cS z)q%b&3h`vRL=Cl{9J*WKWWyl6`ekPf{Zx&2>Iu0`5*jzaDF4*=UZWQ{}6O|4QW(U~r31q@yF@f}=$s_p<2ECNG^csb1ei@=JYz`#hnsnQ!o0s(oF_2LLhg^&0U z!2B65Hbh_?4b_<{-2fTO$6_Fi0gn;AEwb}Pqo?1XG4MSAa??N!$V~;WFfN?9(K(csDUL6&d;zL_3|(f zq`CPi;C+A0@fuZkjuLg6NKjmOqc9SSm2$o+F%XX{q@(yKZZYbot-fu?~P zyIX@cQn$vu%M&m>HT3RhSU`%6x6^wnD$(mgJl&;$;v&LI+CeQ@<* zVBmbnRVj!B#(BvkfWgND>2c#L^qSoC7v<3W_N_GFQxoZnD{&n8n5~)}{V$5~ z;w*}v3WycHG8lA)3tO#s)1srRJm$xv9#E_{?W!@YT21QT5pEbS6i2+J)KryD;wCmx zDI9+;Y-&+uxl+SyHr@-enHLNO;?j?cK{Dv|)X^Jqz45>;)T>Rfr^Dy89p3@G6~zkk znGbW$vxNbgUk3`bN zhaBG=RNBZWHq>2_0^mrEl?9wGk_a@mL_b}>=SDF_tsYuVqgAK+>Mcc<52P%ULFfVJ zGo{~)knb)&jlO7v(Sg`ZJ#S=CtnzXQd0oUnD*cCgr;9M)W#a(4q+8Z4OiKB*pNhH4 zT7`|@rWmtT3L8fAlq6BUVg<*unU6BoG7kSX!sq_}`TBgPP+P-+#x0gX8+D)Ww@&>e zJi;1Ex8}q?4_->6u>Z66mv<;AC`zf!3|U#+ce~cmpDFu`b2bfz6h7EY`jMgpFwGrw zpS`lJ2eF~$wls(0WhkUt1GJ|A^E z6LBkxXb3?VQ>IKVvS$Z+fOq4U1S0*Os0fTUNg>f#P1J~!jsBf)*nxsrWmr2sF|-k< z_giazPdsgk(Hvi7e7TZ>j`^dqwSPidA5c+qd3aM#W){c%Xwy<_G*5iHKd%)ub$f+m zv}plcoiyI}0=&SnpxrDWXv6=S5u*fGLp-n=UjH5dXBF)P4W7TJ%|U`3Ry50cTQ*oc zxOPQx#fXH91^T}4An_-;-G0YWnTZxb^&oOmOk;O6-D%jSIL76^MuBQG={UnNUyJXaH> z*PWpDE`FsW82UoJso7iU=n0u*R5*z!YHsn`tKG97{D_{oKBRT8o?Ib`i5Y#bV}yRt zE07qYf@|dq;%qQm7{)#jlv5&DR&Jfu)g7P zaie9FzxdEHXf|C}t?RLPd8BK#+KDcO;9bP&VCs+XZiLml`4>IJ9n3@;U`{Zvr>V5v zQPjCFvq;;KJnaCbHv@>f)!(%K{VYSNCi$|M8qk8nlIjU$)%=cPNJMQm_pVAe@X4g( zS?ePUW%+}6v3x=~R6DsWZ-0&EsY&vLU*^e%eFz^~P4wzG`|AM%$yDM&8GkS76|+J$ z+1>hybz#Je$8o#UeEH-kV7B7@R4E%hsKrMRBeH_RObQ^E;nkx@XcCiT$Rcn1l!U z)FNlhb_dw_!M3y?WIPU+gA4uR3+{soS+lD&ed_9;d zHwioL7|jl+GvNEaS}xX=NL@*Q=J}pr7i`$X0fBREGK{3gEl+moL$GsiB6ZALdNqOb z{W%hTeh&;)($3RD|r z?%N!%XNWxjrq#*^E8}-qSw|6%p{pOTdWEpjEPQfi&k)?xYKk}{T=G*asy4#yW{kMj zG7)deIxDd0k8+#;J7z8p?o7jh1Z5d2#sOTtzHnjxCEy`a^d2!lLQBJ|&jy>> zZFHQR3*Por)kSR2ArDM}hWmu;+5{fw_F{_{5}o+u@Mzs)-zG_1T`ie3aoW>Tyx!4k z3m_o7uuGSqt9*VkU1k|UqtT!Up!InYXx)6U>4mQOBnr24geal2}w5^$0NWcIkM1^n3$ zFCU3SPTO=4^0_-(to2T1pO}R7{;OubYVnsxmB9typ?kNUDca?Ed|_SEo05L|pyY|R zKfP)to$kH_c0whsm=3)0EM|0aa%}orC1mpTB2tt%Z&%qhmIS{<2-Be|9MMd`mY;7<#^stqmuWCKWGoyxNujGB8kA$LO2P z7%*{{(KsHjjU9e+K+Jcish=Ep%nj-@LLMMO=8Bxawx1unbked!JN$rURMB&?!Qx5Q z?S5FdSu*=mNrqvc`$-5nh8QtC#r^=5Q3NtJlf)YEMyUE>)Lfi7^_GWmziPKoRn3|y zC02VUfK=>z34q@r!1<;SODyBoEMykFB5wg|GPBpe%UfRH1FJqV&3k+e%Eg!Mh@YH4I3?+T?re1DvStFqXB)IR z^=B&bgPjDhw6huYPqlSg*XU(GM@0X=rC0z$<`s&77fmhqbP4dzwO?h&^OO{%lQ}6( zlnaM>3>ex~Xdnd(&hXl3UOX)(#pZoDwB*h1z>S(CUR>mRcI%B)V%ziHj1PWPG`3{T zhWN?LgdacrGk%2ecg{UWQcx?^kGZ=!-}-@n?)E{0ojYLuv(2*)ga9F(QG&+!jFDxw z?BcC1&|Qd7fqHc+pX22r=ENrkWL-Uc)(x8Ph4Z#nYRt10DdD}AXl#A+{5J+M(HRur0*OV^Y=5>oO(CWL2Z83(4UbOVBR>y#OUNFbz8^gJhby$W zIvSK56jMTpba#*SCCRwCHRH;Sh*MH@K%RP zE15~xV53y133Lr<w>n(phcVnwv*eyt|8Vd^X_im)coIi#Pr%{uwUI`O~C z=Q{-&0l8<5VD*slwlZibI zWI=uYCz3*rTkeL4c>hqwA~})VkJh=5sOfc*A&O%(tq7ff^jiv5S-XSjY({i2mAMjK zCUFq-{3c*R{3gr;x1?th)x9xv;4#V+*k`(cN+ulyrPMUyCy8VIaQYJVS?V`n$bC_( zc8SH~veR69yBgZMO8ojLqD}Js*88yIwUvFOwu6iPDH7p;cS=*<`3MfTy`b>Ytw32F zz7g2>1Xjo{a0RTkc16gS=!w(%q9+AzXeM)73P?m!WFH3(h?A}EheejKRiCYoet~A2 zG`hVZq3c9=S33cQf|YIU*L^29s|z-A0}c($#H;(E|KV6ZDoBw1-E1LIs$1$~ zC~-=4mCk;ztY$;a62;TB}mVbFDED+wP*OocY5_Cu0IbcQrYza}lFMBb(cU zhMW(;X_NSEhNeLme;`O?{N(mIQs>@GrQTi5SsdBiWR4C(dv@mY>Q;4RYg>G*Cd2-u zF{7m0=dWsL2p=0KsG#4NCjWYyXDjAq_$NUT$D#+gkK!LF!Qhj%Gl|E!tm=>kSkB0m zSO_YZ^R(;bTdvR0_1YviSK520Z1&&?{LTj;ZcywSK4#gIkFN#9}Uyzv%{P@PA^KQcGjYfkc6LFb%znd)8OVF z+?EUY$fyxx{8H(Eu=woHpsXOdNpFZMAWtcahi)fE5|zdr>RqRls~k?&?)l|E&qvJ&OpWQD?scnT%2$E%n%JM zZj`7vxuC_`>oS?@S2tHHeoFp6a7v~?w?L==-Zb;kIh?yuXzn) z9ks<0BrN)$AKSKK{?FT?0C#De2im`KKK2);dBb8-9RIX#!~Zm;Mj1VR7TH5^s_Zs9ViGe{j+}Ib$K_!9W_z*H9S;$U=ZEwB~O3Sk6-e9wEluQo}ah zNGPpMV3yZ#oha6Nwn=ZCmhs}BerGYt($dl+SCfVH&8x?sPJHgK>eTPjmW5RV1qA7a~M1=(&9I21f7Iy%wX zS%?&$>~YJEKn`x&#NC`eAY;?b;H(Kb%9-OGpx{MlUi`dA6dr`uslvCy?i-zXOC?1h1>e>nkhEw;JcfCNXM?{Sf;IsUAFjH&?wI1`MIDPho; zSklR`Yrk||i0hh?<8d~>eSI&OlDxypjuR697C1@_pQf6$%UGtN%l|i+qzQv3x5CE< zO7(TDI|`atR(HVbczQ%mDw9-KV%25^qQ;S~3})GZNaELOe^ieg`k}!R8(Zq1G`W@b z3S08mCo&0n>GVmr{Al*NB0R5?tECZLjoymMjdM_x~ zz-B3DY3BZZODo!REhh@NXzeNGtBQIK29mfkJ4i7>^LQ;i1`@TAqxki5dR9c=~M@NTQeucmB37UA}JPePo&T7pc8UMDS!Oi0Ebyw0IUwR++ z_zU9J{kpr0SJ48GqY|pEGS8_LSNa$DDlQlVdmAQc)EF0R53Ru*U3fgG7Y{b9mo3c#XVzGY99FA~^Ll?ow!zNW zIISIiH_B$d(U?Y}S**NNlf>(_eJi6pJXnvLih~s4v2yKK7dCZ`ffWN3g6#J9^&}Go zkcj5zNaFK#S9okl-i`8Y-PgRNqqYc(U|py=RcyMPD{(9Zav}wD%|<#}^?7ooTqS#r zu){%u$6Y<3=5X1Ys-Th8rGP@tk~HP>a7MNDy4d69QNKsI7@2A}B#y@<+9$ojWI>zJ zu$z?2&U8YLzZ^OdO{J96UPEv$V?I|Ryxt#ALLNdG)2);vaTAQ64mxC(;cnm_OaI&a zJLw<=zMj_q2Iq%8|T4>A9N)Idjd;HZjS4!OVjNVYcO7iLLOVNKv@(4YCXwX zyS>?H_=_s*4OC#TC`bVN7AlqO5BZ>obqpb5{4l(iw2F$)1vNToKLb%ux#Mx9WaAcv zS|f*x;pvh+W4ZemR)2SD9EP4wRq1%*9G~H`hJ!1yL*4-mpO=(6hCT)`oxt;0gYDW0 zMjWj-#Eis#GMi5;N<`7DSh}mX=R+-xG zVro{HX6I?uOFY;sb1$Kiq<+-+|_B-=hm?)`# z%)7w04i8pl5@Q}ceGgVa0HMP-c7*Jxb`9^cHVjU@r`M)XDfE$?vD?!FSS3dLebcR> z)R@tH6_t=9VFWHhT-CCy*@=?!(JZx*y$=cWV7V*ME|*u%Q>9a(gV?Ec%rnGTF3i_I zf~Smo%wBqtB0b*vMZSE(&eldASelFfxzPBbC38@=x* z>r*CDL#NXvkLzD}SYjBuZgZ7 zIW5Gdz|rjpjBbDtgyw5hY_nC-6@*y*V)9d`ji>*t=3iqg*;DcDYFM=qIpk-k@yLC2 zP464md$lAtgV5Wv2|}y0?sq`I08tO#V#?^~a`k8Z#js>}Mq0f$%-X ze~r3^8xc8Kln|SO@8L96$V;@dy40{-2H9!*CC4{TL)ou#b269r&IjGVn1PpUF;^$- z17i?sZ29zZ%}VuG;N|yUfw)}CHx$>~5i;B#A#N;Sm4i>cpD2Wo>vp(Mw)mn%1Z>c= z3*f`DO-}0pAZl~cz1ReACRfy6>dQJ+z+U!9=4#&rBr3a6X2=e>!F-}mE*9KEthu+* z&#sOR(bk6B0?l?QjB^(2_OxfUrCw>+aoM#^ti7Xw?7THS=+;~Ax*@@PP-Zwb#$P)s>Ffd=)gq+`J?c)Efx&KP++m!RxRt7!v0X@AjX@rTcXvo=et(Yi zx)FJcRDttCri!QwjR&lU3<>HLbutFM33LbbH^Bfo+#_G%or=VlGvNJO>^pt+a3duE?*L_v)Ss>5?F^_wp^;uTdKFt^qbdbCiFQ@VU|6cn^IjW% z)FTsl0FI!%B)zBmSic9*&RzvOi9l3KoyyC&hQ} zK^x_GX^^-E&Xbe%!sI*X7hrSl3Q}t2l-;B0p6*r7M^2R*7`d?pi!SF{>Wb{#KwRT@ z+3y!qJUI&*Z_aVA78cRI?XlQ<7p_bM|F+m$Xyj}2x-p-w>l$kJDL$L$vgjc}Lkk5v z1pfPb!2 ztF>2@7;h;`H)uma@dtDPLqpFSIv0VL&6w|CFgv2|{5n3k;ijkci1BzOBu%cR-SYUo zDn5jL;4;}Ya<10?QMb5JMX!4sjL)Y2GytK^FVu2^4axjy_OKqtN}K| zip{us_iTcTxRt5UE{mFj@wx}5Bze91&bwHhLDFDLt+4KGXKY(Dy_gk$2$Tx0djr_T zZ4b8Igz!<}PnSnqG+wC-vS?YJZlX_>8ArUOmJ=w^ySMlYn&`E5<$B%WYBhFy>o3r~ zmpzLLpwdg8?5+Snvz$zvdg}DMa>ao{5ueK@{KRm8vn~lvL=PAhY@W}nM)_h|?L_y< zmx@TeL_Xeq>E2XkwDgomw4+}O?DFAPKW;~poPm9S%DZnD)4M>2p3w)Dq?yfOdzj<>N zbGNf(M$zipG5Zr^BFI;G37&Ra0MBrl)?#_b0r0>^kV|ha{QgTMs!H7KdvoS2re0>0 z9U^0y;aIwkN`^xuRAn5Ify3yqwd}T6WPd^M$au6lm}eUQ^L&1V$*b>RvZ7D7?~2oP z@6~jM`CN^B@i$@E6igm6;}#uW>XVBExfmnV@GKUty-- z`ZFX=vFqVl;_KJY;3>e-%krK28@z(VxS8UCw&U>G&C~Q;2?2tN62VhzFPZYg``g)^ z9X@Bb#zEbR75d2bC8ynO7L9tH7^mGX4QP{npT+E+$yFgtMbCR?4k7wN!`sF1sH7eZs=~3iD;4lBGyEE>ruFn2YuKDRwo6 z-PF;ZcK{}HlfqBRUd(Rk{ApX}TABvmjg#KkkrLY(WyjU94pLFOfggxEX5=!7;ea#0 z&C*At_O>}8@t_Sl}KjD4)9%+m6^{d1HttfyRBb^ zr>{=;L4^LoJP)c2{J96Q>1|sK#ICjjLxP0ym1Lmda`#y7HG!JYQkQKxUxl_O!f^e@ z-SLoU%b8o9#dw`?-S!NX&xaiFLu?fJX({myQK2;^nW)}{c467 zOwK8!0Gl7EBQ`Jb*bmVq^=;T1zU~ro*oaZpUCJj|%KlLlpUZUu`3G}5JCuI7?UY&a z)zAb>oa6*VFi@IKNs06S`~nI#+qNYO&N-g@UP!ysI?q36kfeEN}M6$8cs=x-&}s(D?J9Hpza zI*aTpJC|hVPlo6hTu(qE2vf%qjVUNzSN3sbuvdE6umg+ixG!*TzWTZ{s1`KXDZQyX z+Z|GkhH#VaOynyFzH7%n|59!|A+7Cn^gQ-Qy1&aeh%P2&;RzcOK4^fr!WO*88|O0w2_M zBA4J9P@f%l_t0-O^wW!mSnmcf@x=^bm!XxI?9Y{oHa6XS6An;=maeu#wNiJp7LLlv zw_F7s26a@qc{arzf6EZgsleM^Hbb&Sv1gf$l%3X%o73< zuF!$5uc+NNM(FVLs~39i+!f5hjCz0vO zgWpMlf%JiWk=zX~QB9#+p$n=mZQOE={4mFj#0#4zsIkkL4<|Btfh`TPL~f@mhNuM7 zgc~X`bXt)kh67^3yBwtTF^3M|C4{--{6QDA8EC~qB3PVRrKXDklv#>Z&s_;Zn(;k- zv6;du>eo|ebfDua6iKsQjs|Hso#L4t3yYW2wmVR(&~lUURyAW*-?BLVU-ZqQ54XBG zRC;UQN;I8T8hHwe2}^&NfX<(4lGCxJs8#A^bRTBu6ehOo(XXf63Wd^hHQ{VB1Tls$ zUZMtr*gIz-s&t4> zk-R@z;e3Regv7pjJ|_!Y0qa-0#24?2ll6h2gF5dHuz36NR9P~q)9H0beu@@71^kbi z^1rc>jE`?M0MHE!tB~3=MbNwPc16sTYnH!C>hNc{1CBT2ryTH|{rZy8ooy!@>8^J^ z+NJ#}1&YEu_~ z#AVGJNfYn%Id%buPW}aK@0VDt9eL2q^=>fsQ)^#Ovn%x`%!n<@35Q^=H4&6%bP0>qSpu z;Nu7pZ~F0kEW-b=s9>&El2XA))unqKNrYk#m`s_cP`0PEHt|a;{@n67^Ab&2>y3Oj zjl`bfjb}FAW=HL?*%?w`HJc?8^hF8dgZEpsmT31+o+?eHmJWUm> zIhqUv#0mZjN8Zb?ZW>+`*YXpwj0TbGed?XNu}o*^BxtAmB#y`HVRN+?n@sLtEzJsf z?MF{089BOxhR-Mzw1B$DwH^CNoQ!b0Q<`_VG3zth_PY#(SY1%6oAnSfh?yY7s!=H_p7vsB1iZR@K6C|Z0Mq7Q(W2pXjjB=mRy8`Mebjg z>oY>4!iM8;P}pa6FVUzm^>n|Z9>opPQ|z?b4YGPiwOKsL>e-h2zE1<%fXL0~+|rH` zeIEWs;Kdc%<2^(cdUL)*e~*1@+YB=pRB&oxpqaMcrSMF09nbHeVP_V)z>d2>UE;8M zaCR$lVTDE_-z>u4*oA;n7T0AZ~(bk!q<&kBElcM&_?j8u<+9W zKpltIOd=#URxYi1PpvKRhC=+y4>F5IOVq-~s|sG!KBF z8dRQ}S)^!8O-&D{?YY`Q18;mLgEHR2cSNzs%>fz}rux~9*PO0hbBFq6-`Ev<<%8h=TS(*td=tdPb~}actIQ-7Dy>k>kZ48-8-?1I_@i)C<+f z7DwJIn>1vXtmITY`nuEb)6J=#;qy0mC#OsU(E5k74#n8R6B(yqOo*$}eq&>$%k9x& zYoQPj+xi~eTo6oMg~0qgJjUPb&*ob@ec&F3DUY?n>3ng(;vnF?KO#?V|K#3F^u_en zD|v0kqA}#;(9Z8=52Juz7*V^#HVhUCP!IR-2MnbG(*%=23+&Tgh&r_ zvULL!PoaMG#G!t3lw+(2G^>2J}hzdDjKtsFk^uCNt%#ZB?58AYg{e?;&JETO`c z#{umf()TS5%BOd&1xP2CQk|NMJ-32lR^k6)4(p_-fc|S#M`*E-t*y+}6XAHqBI49z zH(esik7;Q6Vm`@a8@XU-#{%PNq(d%(f_x;3Kk9k=hm`QBj-A#_JR?juw}~l6%e(Xd z%-onfAR7(WR6ACTc7Bq3ftb!gJO!&qPcGj0@-4xWl)j6WZ_mX|^;SHmV~=$F@=X8! zaSn@vlar0C=TRnbb^H$C;2tuU42V;RuZ>XhG~XQjJ*lu*Aed@^#eYd)(0**;T)ZMD zKV%QYzf1p^=5zz*Iuc3;H@W}zlOQoG`bie$1PWm~L~nuQylTc>_`|Qkx0fV+27WLd zF^0FvhrM2K7J`{{TALAj9PqnCFVS0#6Azf}5s6$Ulby{`p_QY4hK3kpE*op|j7x zTCxhpbQNH#{*PzK9(S{6F#e_Zm&sJ_MWCt%Qu-pZtAG7gt7kq#eCEH1eG?EIgO6p@ z5AW<0n~4tj$Ac7Fi*l;J+2=+2ky()^6fEY|)*Hc^^-g0I`lSE7@T&O}9_(wzQv(5v zH#j-kov}=rKs)8#{% z69c6F`BB9Fc(#fU`l0V5$xxl@?aPpfKS5DK`g-^r*av|VP)JBf%*ZGU^~=A0neuNs z_mSqXoaM3iCBrdra(LaFI-iLD`%D!_dOWB9^~rw~2iAY`c>xSwkMcTX*UKfut?~SL zz(*t>pK1>wqz8AUp$ig`z)%{slA?wP5Bmj}N`Yqehv!J|BSFyFPEzCJ^>gta=x&8w zZ;wPBL7?RtkeXY*Dz;n^aXjuK$A9qk_TG8`1A8ltMY&XwE-*+mgAD*3cvJ}QH7F|X z9RbxP%5~kOI&r7{9Uvr+=+bG`L{3(I4)=SwJ8%P0WV_EGrtN{)$72A^=9pr?H%(^I zcvmr7Wl7RixYj#ath;t|0PaH^?Y}Dj5ANP7sII7M(?x=7@ZbajBsc_j4H7iCJHg#u z6WrZ{ySqDqAi>>(yE{Gk>hJ3MyQ})@T%2=mvIDHW_mVm1T4RiNJa1Kusz3zD!RnN2 zx8d)E$;-~R8p>oqd+{c70$l$Q%Q1aohsAgJs=k(3=R&yS?vNa6j~6E zx6^pWJPzba#BPDayX-ms>#%-28z5PzAPqf4HpIcH6rYHRYaaK5L9%Fq5PLdV@eA75 z+5ir8fIqB^fQFU`vaVE;WGU>{^uWock%s*eK;njagE8BP;UcBL$=j-%)sB75ESWgh zEEV|z++&eRAA$1X_-JGEEKp!e^#q|{)=ia{f6EnrYdV=9Za5f4_CZCj)u$UO2Y#gm zaNtw{uIiU$&AV5L1ZbcE7DRcqi&8kxPd7TrjCy{WjW&X~=NLU%ubB=I0Q^3%b;5u6 zt(HIzLQf$AeEbyJSt+wutGi)PX9Ul^gTRE+B-KtW-5*q;-vvFdd_af&aoPY{ScbrX z5s7IC6)FKYfs?!Kk<{kyY2bH_fQ;ZiwLOu^wP#mNJDsp9O;wo647u8mgI27cs8~8(PH);Id+MwHu z0?@hb-H~xb8dXK$B|ZYZr&Os%gN)g1dD#kaDJi)o07+ONd_wNt-=8U?A>wive*w5n zu=)T&bNb;@(>JO@;FKZ(Y_o_uT(^@=asi&c8W@>!I_}50al3=$^sr5T2uqw?9Io!w z9q=Jlte{pt;J;mi9;gC=>5SY8P)QGbBItfU5cY198W$@ZVB!{xn!54q#*LVhpJ8v|fp!8;lahe{aL@$#(k8r^`}`FOJr+@IxKlpZ%w zeyn!AFmCdCY6iMIA!3&`$d7VaK3%> zSf<+V(IOD~2vn8j0KcM8p#dazT4n6}5P(7a-B&*#%ED!;^49L<>Bjs!IhM7{1W>Ky z{A0!XN^`Y=Jmkmcd!W_sp@z+T_=8rby_INVYpls#yO0@2~rh z$1pcR&p)oe&y*(D0vpRs$5R3kWRHiVh6omNLy~Nl-4{IXpM(M=-JBmNMG)NCNW5Thu0Q-ZAr?IJy;pyP`H1^@H70qLZCBnRvhfl=>!EwILHP7Q!j z?~sFDQ=zybGra@gqw@JuvqY6mogcv*;xckkWD`9`xU1hkWc z32kLAC!JSZzr5T~Flg!-9ix-%2-au{^9yMKmt*A|qBSGY7oP!aPdI~V$p=*Y&*D3j zVc3H(gV4KZcr>bMLJ!$157$Qo1*`ZjDgLC9avk4=|G*tQ zXuHCsvFn@VV)EhXw`Ls3Dq|WDP+{)W40ssO36uUa58MKx0UDJ%V!qxobx8S-`7YJZ zD5jqkwCBoHcn?Itii{UBG%E@&3fGuuEadr%0=;HJE0VyPUUwi>6|m9#ghjR#1BKTM zu%^+#2U89fm9Q{&1>lbiv=E>OgQ(-6;Hkc@QRiSYB6RNh*vSFBz2}KVE)*U^rss8X zyZ8NG0g+eAw+1 z9E##*4DRXl2ENOR624u5_8dPxyFtV5dfqG-U{X_J)k0#y>MTHDl2U4aEr-wUrtsyJ z9d&2aMeh>-+}$n~L0E*z54Ms9QU6BV%r^p|cU>Z{8HIhvGtMF7a_FxZkdTmEWLMsdj*;My@3c5cNt|#Ou~NPeyNXl<@&!75SyXRR2~NJXk#5ae(whiU z@EzCkIRim0e@P6x!>(L<>C5AV>=9DCCS1_R>wbNOALn;NG!=zV{(&Da)mV0a;NeoE zVP)!oBB1)t`CDsGd{0z&ioZ^HRCrRr5m6;@o=EPx(#7bwf)O_B5~Q{%t|w7|&os6Y z-Vq1d0xrW8(S5rw`@F7E+NMh_N*vV`bQ}q!1h&Ed)B;dv!LHmV_u?_!5@DU-YP$$x zGcScgF5ohw4$&N=ZN3d*ypLwVtBIwORVMF^_xopx-0dRR>(k_!_4R!+_I)ioPq=3Z z^FUa`weLn`-y~>s<=TI{i6-`|p{ZA`Ud^-s=+3nMAuk|QBN!lUqQM?+M)H>%U;u}e zuMed(l|K>xEiZL2=?Ke&!nnTG@kobT4<7JCMi!eQLjDR}`>r1sCsAIuy_UfN`;T6+B6X_S;`xL4m9)51S}FzokSH1Yf#@z@m5lyEIcZ*;{kHM6>GsP3vzI>*{Gq z{xeDy32%-Iq zq^;(1s_gU$#Jyw>8vuNl-&H?WUk5kaXT=k!B+Yf-&HyMhOk`z`1T5Wu7?_`6nRtkj zXtNlTeW{ST-_SgrekVIb78*fRwd@Tcc;3+dQ(|p=$~y$Hrp36@0tH19OS=zq6>yV; ztmn`IC4>@7)2e{}Q?vO(` zgnlRoWiuuxQk4>pZB=3kG4^MpFH|YIyQxwio*V*^7z>uAkcQf=Uy`ak_@1pHwxr&6 zI;fGp)uYjxwh(+ULMLM&lbMgX9vXFd;JpxkPXL?|W@eXEa678eSXjIplmCU_JK=|4 zUcjC^&oboq(taBhwHW+l9}+BbE1sPCnTF4O-w@-FKeqOzFkV$qL-)QT*xS(EB|bvq%5c6Mpx6tl557gn}0OkP)J#)|Hez-IsV;pPTF~AgQ;9jc@R%$0e6$+CeVI^w;vsc zkdco`W_?fCGYJUT0{C-)cYBUW( zQS1+5H}L_)p$I0p9?ah-oxemw9W?byv(l1!s(gGO*m1-djcs{%m8seH(TR0f+K1kk z7{C!L{bAab8fTR&pzctedJ!KA%I^4${DznkA6^z3Sq2^vp1^vYpnZd9-XP1Jxt3Ip zv~mo{xK;MyBnhz~HA%>%V9`B-28Q2F5d_dul0x_FGIm;%F;+E)2ESwYDwctfpj+L8 z_+D9;Ebc6|cg`Q)A10)fJ8codo9S;iixsRSfl$C77j=kJ?9Jv=va04^T z`~yoJ@(B;Ks!69iHQ*tDIq3Pjt`++f$??aJ*Bh<}lZ;Vs7lI7=U>lt;cscyfyLAP` zsk95fQDe&awS7onz9G7Nt9#7N(eT&0bP(2hlW^9*8?oXI4n`I_;3>5l=x1kUpBNw~ z3D1wqY}X4tysyO|riHGh8VzJr%IR27gLe){L^^^Jon!Rr-N5U8WOCeBL^<+b>a5GI z{qRP|Fv3@99>oX)k-oL~I}%=$vQ2{J$^ya#)Nz-GiV_ zaWU-+>c^Dob>aN$yaEn`+0_FcGI-q(tLrX!8>8zjqfbLBYKD%7NdxV+(&VvC*iVtU z7T*ggSyZpOeMFLSE`~l_m+DSGSwRcBG{n#etU-N697Q1e<2MtA9Z0-NE`m(6hyF{I zw$lqaK%*J+7<~vHp{JO6PTo{dp?EEX{*4gQSz0j)PO|mMqmyupG-2`j-{a4Tdt%CEeY!QQkkUGH{4 zrMxAnFdba*Mx!4vdsA07OK2s-s(QA}Zul&g4PmpzPYZR&5Uz#r7)txsxpi*%DPfHv zgQsZ&dXq4lNCWy??{_81WJ-Ud_#tW=QIpEegyAY{YaMyUC!M~j4L)N5;tEnQ ztc}JPoeej0+R>S#fvh}q3_WId38x&R`!*!r&9+^~CDjIbpS)d?ejooqe>^h{8*`H@ z>GL`(ld|2WJzXuzJz|^&^kGTYCwqMYjPEpQvrVhy0Yl)re>l*>Xmi@K(Oo4k zVFOV@QXxmf8Tl?uf_<@H*V~?ppa4EOfw$98IXI#I+oHnOPsn;%c(~i+f|o}2-eT$G zhNuIaiPNQz8*SN!WS1BNorCOKKc|^~y89NOxzGO5CN62je`p^fEU6|y0*PnQ?_@EB z96y>g(xqDKF!=_W))1H(Ggv~H)`siC%DAW*w(;$MwcHLOS=)c{*cQ|gFX#M_ZS-~M zZXk>uAZD#pqyN|B&_P;Jp`F3Mpli)!EFa0TUTY6)LiA352)*zi=NtOfn`BrG)K zEX?|@D}(`-;d(}ZI$39s5l(NHmNo{O+6ms>H%hdh6Q1$Ho{CHy9RL8(;Xjq$bNf&8 zd@U9m)DY_Ady993giEjJ8-guas@RN#)Yt3NM#spPm6Q_(&(Gwq^xe>`_ZfAHg=Y~y zhsmUk#o#NRxS0XPgwJW8YgqhO7e4fUxDR--Z?A0{B|`!|@xME#K}$fM@?*KOfQuV~ z5NAcf=5rn?ff!49jO`xS>Razy72ww8y1c#=)F?~wRlp8H)e=Tn{g3vtck9xHx)N36* zyDuAXQy=$nPUI`LPi3sLI`lhI3eZgk(F}b867f6<^!#s8u6f>h_DW_3IYVTU2P5^v z4TZg-7CR?U$wD3XGCp0*J#BV>jh;A>-(2clnuf84X;4dT!(f0BF$AJfMi*U&>yJ|P zXxvfNWNz??=t-7sA5x*3?*E74>d~M-b?JhVy>w97`l&ZWQ$jqQv=!$nlC9r84i5HL z?-KvVWjo*pGye%j`lI^+HCZzof{cbRfFzFeVu(Vy$5uyfh3q?%?FQH2 z=Ur3^!pR3rH8mVR08(N?$m24U zwYwfqp(1}lzg{Tn(D)}UYRr3VW-k2?b6N@NDwgmDsIi~B4{fyYw8c^5@JjBL_xq41 z_Hx3bCEmtzMZi%fGTelmRBeQ`>%&TXL|+L6%4Y01^-}5_hIRW3$%^=cP6J=BUrvZexWtXMiW*O4`KXjUEQ_F@naV921yi6Ei+qJp8@AS!8hJ3D3^Sfr0~n; zU6Y(73K|g)L!&pfS0O#rNysRz{xjbS&XE$v47hYEae>vp!fBrED?~Z87`@K92 zBO0y+lSuaAgNl0xSw(OKz3?MHRBhEVuw z$M2@-PY7N6G;iq6P>^j7qnR`Qielhys?{g;E=A)nc1pHI#eo3qklhas3Klxf)n3dJ zk64w^$IgKPB4;425ET{{gNm#uE;@js$rlPGGR$5PN(dv`2p^V=thaqmzPuOCx%wvs zeNo?W_LtZGF+ZO#P?7rJju-E)GGF_)I7sxJ;TCHv@<(iuq|Q*dNVqsD7yZf@v`8yE z=t%DFQ*`DX!f2lz&TfNfENx~X@eO^dCJYju-|vMskp9CLLx9bIFv!eefj4ErP;qsm zP?UrWRs?yjZFp!A@sC2D%e-H>J_@FjGof{#r{O}Zg$pt#^m73ANp8vm)TNfYLZghV6(<>Q-HdmI>kp_Aaitu6V_!C^~cubY< zO%Hz1r{wewT&t{Xw?v<}&E79wO>S4kQo>gNXL^3Ollhwe%>}4IP|nPJe|(T^k`WC@ z;vx6yq?bD@xcur{$P97?2=MSW9(4#4>0iXlCsQ2#KeX`_Lmy8c_xAj zMJZGy;emjJ6wAKiBCPFx#QG69_r=U?0`T@fpsP;=0i`%VQssiId%Z;iNT2)$Z2zqu zH2ye%z*@)>*|K7GI#m4)?52?kIiijPFv1^6WN|nhX0G<`*_4E@f&)`UQ8Pm?Six`+ z7t-53(b5G{i&t_ukkP1Yf$%=z!UBEI2j)FqA86jJ6HNwytM{^ecew#UK?_-*DXJP5kKEY%k5^Msf37}Y_MWWE zZ`}0aD%fu+&O4s#S0|8tkUz@#xZ(W5*o1HUbR2g-uJ%!_Ea32YqllvdSAA+i7`4N$ z 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�!l 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 diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/originator-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/originator-attributes-ft.png index d113c4dc83305535f2ad9df0a31d78d681dcf2ee..fceb295f4d0be89bcf804caf7da4561eac953ec9 100644 GIT binary patch literal 30258 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 Jr)VAZUjPrBieLZ$ literal 86148 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%0DXS-Kh`AX%tG(A1~Ey`y2%PyN# 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 z

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 E2c!m7Hvj+t diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/originator-fields-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/originator-fields-ft.png index 59919a33b4511381332430ec4dc4ca846dacce78..750c7d900f215e4ea86ca4c86d30272885a79c58 100644 GIT binary patch literal 23958 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

Xpc@;CYw%vzPIPex^r4oF28XR#qY) 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 k3g7;Q9HCC&*Fsmgrro)kXgs@k3P|sS0HH_? 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

mb&-AsG3o*1#CJ5GI;~zJW$R;>{JEz zW7gugb0$5>`&gL$HBZVv^9~c^c}0Mujm=sdy;vV-K?vJAk74`z$1TE~@jOgQO6E)h zdLV^E=R{08LMo5wUpz&91l9QOL#bA_R)TsX^^b8h1*$y%l(suD0S;|{2+CWK8{9zzp_xF;0q|W<#26Cd*NB-w$7#e-XpoQ=SqW+{Rz`RvgN!mbx z$DfiVnu>zdB7%I^DmkP3f7~M8k!uE{ixYlj?nTR7Rp2ZyDx@TX);>$0?x+CfYdiES zR|FVQ&7!N;dRtLN3r+>JxCUCtTy2;It=NvI1k=*-Q?Npp!g?`);nX zgb)X*_9kpLg^Hh;wU!Sq=+?h603g1Zd_|>LO76`j{)iX~IzIfiEfXvT_~QMg^RR4H z+GhyNUxhZY$~j{Yb)M*BNXguEn$)!D#3HsA>6^3(A6#VJP2Q;)0bZ*^uI9pWfPKFCr z@U2_7c1Hm->e5OYRfb>$Cz2=icj&fS%2v_chwR6MOE!5^As;(NxvUqHfG zUNw2Nd1gZo4#^D&@#u|b)O=SU>YP4#X!-(3xSMU0GgOEH-rJf6^ITsn!GxBPR(4BQ zp$8M{0_yqF`72hH$@n{z*Jp|Z!(zY{Y6QR_$_vapeBL^YX7O!L*QC*24<$cSikU;! zyWn(9T7FvzPd9qKvad8Q`WPysOwODx3lAPZB)-E;)upsvGz1~IDc$_{7TF8JP9i7Y zL@B*i>Fj`)I_=v`tmk8)-e^CQKYJmwjkeK4R<$Z#YbvOhbLf0pz?JJbs4-WHhV7cq z{AmQS+;icw(Z_Ppc#ZhG1y`X#gC8P@ODrzPCz>pz4w-jz+&j|O2h#^j`optemNG#n z>5{%%>=N-z`~JO0az}rbwfk0-u2sQvzIJ`TS;~O(xvkzq-ko?^Rc?0S#osB~a@0#7 zBTKxIZYxIPdu=GtLOQWbK!FRY&45na?HQw_Un-uMysuj>ETyr^sNYJj90l`@R({nka_S)70Y!J<5`xI69$szh8L|q5npc^Kv>J=ML2k?nqgzwCwe_R&U%! z4n&m@{jBYCMyX$YytA|2KN3p7s76Gjw-n9J7`hA$C)3qY!S<2!l}GuL9;H++$8Xx= zg%Qu>>4cQy=Gl~Gwx%m*g*p^g^a^crU=dFHUvTY6|Slr*S-7E$?@)Z6QO>9W7FT14B1R<$B&qCyw*5#{k9el z37D?aa}3-Wk6zy<%=tBb&-EgR;NiG@1lDg1ms+6wwA>}n;r{C@r7;JCXG=Spmq8g@ znDTl?R9!|-=c)>&Df4ZZAM)|Pb*$JX^mWslW`;Uy1ApYaW(3kX<+3mba< zT9T(fJ=Ff|_YM%e7dd^6SAxNk3pK`SRkEm8J@#?4@ep z7AENg-Fq#hwHSKpn)M7|)ufD!BD}1n1KT6;!QHHRR9jPM{pq`S&@as_AT8g%Y{qGFRp#Iy|%98G&yRAl6p@^YC5Z@f#BhlaXXtG=ZrYV2k5Ny4S|B-!j9%hc z5$Sm|L0U-vg!t}2$M;Yzd4#YwQ*bR5Fy3BDk}${q5=^M#7n5$!5E)|rHo_LLslY%@ zhlC>s2T>SY605RWj-RV$qDG7=WjKvL1w~*`_dn$?OksYEn6aYbp*$(&CbxxW1V7cw zG^c5*%y)igiYq(^227AXZ<##2b$5|7T=QzuN4ReMk0a^(N6c)EJl?Zjo_A^|yj+rt z(I&7R;5LMhz_Me8-nd1~Mgk(BV1rPqs@!~15;7`nclX2kRpo>-9K7DSfPhfyHW_M> z0q4Gz9a=kx=9%gB3OX3XfL49D`p1h@FhzWy=IAOCQk`OoGz(;r1*ST%3@oD4%x|khD&gVYW?OYN8PQ!I0UX`y=qK z>r%%;yT>tziU3IcV&fUFOUU52@&d|eX#HM%$6XXlj8&L7NkYE*6KI3tbhs%5yJxBOV5;&EhfaTG6@JOSC{fL5fL`*S(&HH z$GdI$3$XrDbsGCWiP0s%M!J>VU3PhSv|aaP*JN!}Y7=YCowmfTnepxMRYIh13-#%@ z!HgF-OP_bY;7XM1#3>$4{jmm^D*NqG65Pju>48e?N&*B~hEAtm8sZL$E48ro#b*KD zBA$ZzDw`Em($0WC=0pu+xG*nu7_TcATp9(@IL${{hja3j3RH&zJF`dU!h6 zg;?9ASKFQu@Y9p&SzG{}VL>SN&f!d_dqK5%tHQ6ai@2jbq}kO~uqkNOT;?z!%c=&g zJ9AoihK9pKh1%mxTU7HTe7Q9TuO;>=Bs>p3g&bhe1Zdjm;t&I_$n}w0x%wx!(?d{m zaNF3HtTOb1EU|gXkEywEA+w7S#8J)xJ0U<+Y}yd_qq`mP+EZ@%l5v9@!#TpC4Go{; znL8GJ&WQW+zr!8wm%9_}Ujf7tK5=PQ3fuzMbBzZY z_?mAnvqo!*zv~S&Y(yNSB*>-O^r&Tm+8$Y9%>n*)%JBgeS?04x1S%?;yHxBrs_HAQg6u_<1 zjOhJwx=~61h_dTSzx0-u84*4W)M&ZDDWl!ygdML~mqNu2wemHdJa^A&2;5)!g!6*j zB_2e%ciMN1Y_^U~qc`|Wvjeqgc+KC1TO!4mk^8FY0svGzd(6%{(sz~siM$%IdMPkI zuG;%7I5;RX8<*($OZdKm<+HzL^xpz{%SQu)fPVeIk! zIhcQfNQITvNWKiG_r{P2B5vvW&#K1tBc_1sTSAUl7u-(0wtZJroNlYvdj@Hrz9D+E zIt8V`ZtH>cMfgQ_rIqa2ZyA$1o7OC>61t(0%Dv5FSs|*~c1m4fu#9Yboe-*Jaecjq zqfS3|MrKOX$3`&WzP^Hr!_)-qaISpk+h;H@K*o>h_ygI_2)lZS|b#YGJ|MG6~B zbfUn_{gS3c{o5YL|HTCWl7hbP#ujFiNS>Bhl@j5O39-k(QcBM-!hrjZe!6?-1&gZx zJF-$%Wm(qFcxHjYbpG_jU;dqrUg@Jv%iL>y|>;4>v~AM4gS) zmlZmMoc=tZ6}#l3%yj)qCBPr9mH&)6Oyo_I+aeo3f6YXjrWEb|kV@dytmBYw6EF-@ zdWg9a^Mr*SVc|_&1&j1}`b_t6?uqx(|PNA_m^{$?4B*McvCw*)hkwHJ$ zqW3?sX;!lq9|jocgMPWz`1`FHJhIN&eZ@mfr6=#xe?WfW-o#2Pl%yyJGELm`1$*I& z*6V+dM{rB*E;=J~&eLHuu}d;c3V2j<ARS}J$`CyZf@R<=uwiEp6_1R9RWD{e1XSJnA_>czJ8-*_D=oZLeA@dJTe%V-2A)W z!d;)?8lCGt>HmGv%r`8R9gMx*tf|9JV9XFwxeE(it!P3DUC_TT@9!`Z`PWFXpU#WP z|Iec|-2DC3u+~9ze_#DC9G$T;f>Bv)BtVL+68!x9D;paeNl9i8VtH^Dl`6cxFp;3h&f-}CKcypI-Ij2Zs+J!;tLVdFbocpVs&!Pk#PqMb-}=J$}sg@L`c|;VXHr#LoA# z{1$J_RE~W!Am(D*|DqdHE)ZE}I%ld`E6;k?Z|(8dqo&=dA5%zkTA}T+u}Aa) zTiXit#t;7fjJj1u`{_B|E+$+?Ewni~Io8=ZKG(|L-YrI5ZiA-@PN7cST)(G|x_vr3 znPBBdd;<56Tt)zH5^j@}EK&Ci$EIw#|E_y8F)V`_3~z*m(ZEjmA$b+3Uz@6na*M+X zO!-ylbEYCZ?=6B0nUP@GtD@bXQZ8}N(-a1!cbN-1zfI%}nw>aB1&b7hhG#65td0s4 zU^n;u)#W9wv$ONp`HEJpG97J!r)*Jo#WZe1=BMp;27BqsFC|?9PP2Ldx820jVdbSx zn}iCJR#`6NHXwrW5uX*TkUy{4VQVhxahdlYKG4@EJ3giMgOkNr%nSS<_OLyu2Gjj^ zvjzGLt^3=|Pj_d@dul&m_o?LLC5KjNO@r-UO*Wkhv%XTNF_?DVz3i1^uCSkWn63%_ zQ)R3RJ8w$*VJRc3;Cw@k9eYEj!$#M~`AU6GqL=4lm1M~F@ji2=kW&iw$wCHP`32eM z*187!1&zLb2H@az@%G*x6E=k)xS$Jp*JGMUzt%s)X9I>9s5l7=>$h7sIxKbQ!&sKx z(ZB4P`60Otwo95ZM4WawSN~mXCv2p@AEx2TI0Fr|Mh5+ZK8DEc7<_Dhcu<>y=|Yk0 z=Yw3g&CNhEzI(c(jiB!pCiTlmtFu(8H_eY@58CMk8~{ttv_9cyI=vuC?o8ki2Ju)zE&} zb8)G2{^qK6we)k}9erQ&=_Gy8F{#^(4hFPDc<+rc+0Q$rXxr-Of)%ub?=IArBo^3+K{HBrT?P3zaN!nF2|$ z65Lq#&08w0auJh|knlD7zXIpdgqvo0P(; zE$adE4`ZTAY@E=={2&|zgdU0^)e*`|7<&`Y<+T>u8T#%0b2=Ft_2}5&YR@-de0)j= z1h;?Wf<=xicbba}y0ZO+yN9)w_{7xAU0vaf^nlR@O*<0HvmCz%&6<|h!EZKPhE*Yi z?3%+B4D$`{5D6n=qrt(y+UmKIOy+d?nl*XV@}{x8G`MH76~Q{cp%94ITU<4TXuC+SRzSaZkt4JeHW9tyi~tSoF+}l87BByBPMK-D7%<1&hJ{iN9gI zhJ}TmD-yn^HK#bM?Cfb=g1xFk-;YIf@JL2d`#(M-BJ9G7V0>H6=+;IyaX%Z2bk3HO zq`DKr!jJFgc+j!1QY?q!N1uJxnHx|{vD09IFjLxhg2`O!- zbp-g22eyec{c4Na9nO$b&laO&*X8=rA^A`g(Ed)d9Qc)hkAc4MxQE*s?XC7k zi8QPHeabfS@>5t%`Z`emN3%8JYB}>^8}QC76alZ2W*ZbR%QTlv`}*m#h1eJc`aYb@ zc0R%OVQ}bq8)$c*yJx&)jR8zT_@U~n}cv8KL*I@B0 zlsT!bXgcEDu4!;E45G=Trn2_R5nhSh6eAjeENCSVl|qY`YdV1$jq!t&rncg z&`1s&o8fzdhEjPY1yMq&;KSdb$E|?u=XDVl~{TB=tuCC*gY;T6=0IHeSFM(5Xu!b z)@Xls+-4E-^S8XB;utKf?@e#X{ql85-k;cgJIzK-2Wns4{oWZ^V>(4>-_2rTQ{gN4 z&Z>wzo=#w`aP@X*qk}7>Awx)nERTy=fHb1Q7qZJL%1OcO`JA(HRCVPv$4_O`WOEmg zYh&j5c-MK51A_xPwZ9!x`VZ4>-K;pbbNYMjY3pDdRb!HH*0m7*XjS6GRSQ3a#D+`1 zM#;Xz#?q%VZSZ~$f^L5ygcXV1Q&6J899#Qo;W{M?+) z4M_zVePa>3)YEFc`P*4+Eb$TwMTMnv5VYN~^Pf;nB(*QC7DB(*Jw>LM7BN zj;F;Ro(g%ubXd3hz4ULv*vi=Wy`g(Ag5Um8N&os7XVYR|(n!k-6s&YM*?!(&?79AT z-iT-8y!)c-GiN&CqDP-Y=RZ1YoE7W^WBawEhT``2vyma1`qtl-PMJ1^Ddw<$5_v1)e zjCil=WQZ?pN8hX6l|@vx>ogcK+fz6;XJC z*AUKh>hcjeR{Y=V5_W`)_m@0x7&km>_Na<&>!6@`whT9!<1ug?$cL*?kfifU@uU^~ z!54uO2(mQV9?`lNKKOB7dytc+%6xWOALJ|-ikQ!Kk>htp(3N?9Tu0@(+N-FfbP6jq z)Z_=tthgk9JQYOkoEO^g=cgFiMak2dQU?ziWb?D0Z|7e&>$5rr#Q~1Mc*T3mxY5g^TtyJDb~^$2>PI6L6Vf_<_5_ zRv(FD?1XT$E{#i`W52yGKF<-In)F+Xo%da0o zn3AJ;uSt>1YQklC{m+3S7*$XYePyTm_tmSBO_v-|k9&%17<2p@6 z<|8D2wPqQA`%84UT`))&kba{P4fp2EZGTjuwVr*^xJ>=OGy72M7V0^1U#lVC*pC}S zld7U4NQ1EJPA|O}CEFC^QZ$Yh_)ZyRi6h@b>r7W}=R>X?fPy*N?;Wvsm^2 zetlev^`GvcZ3BC%{{K!WYmAgfcC;}v)dQmcS$SbZII1uI`x^F+7zTa$|C|Z-EUP3V zul>IVBFP-GMwMdx|DRDI<7xlj>P5;gq%C0k-w}q;dJuX5K4xmL5^`ixH982{Jorz> zJaiCYJdpj1@6)2Uj+XDUh?c((5(75?+r})e-u>exij}$JUjh-`=(7`Jz*eaMYS=Hl zgu&2`p~M&9=xiC6+An;nrTjrXj>G2<%$BW2^BCb-L~ai?T$PLKJa-Wq%;CiQ0XK701O}(h%ck>W_v=)zb8cEDxNL+mU;_z@3k(+*82hR~2 zM32qNcugWroinJA>HugBWW?3l52gLUriYmHUhUgAeO=uIret)(oHR<$sl&q>*x?3} znMZo~o%EqMhjT~NYF^*;0bty(*>r~&XFsnlSPPaBXiFL7LWTJF9In*kT+sQ+KWqTo zRvw?8LZKdP!7}eesmP4%!Ywo)(L8&!7Brt2D@%gXzIlE7*xJvWIk9-TDSh9)YnpD? z@{o3Z)Y!GYzS)q)mRv>3PVlE!hJuPrv%`ZNZmCD-?C7YmD#s*tNI|beTwbdL?^jZ3 z1lsXsUfjFbJdEsMeDkxq*H`^ybv-qtZ+{dc()4OSW4%`hsR3L`^@+8A&|@K?FO_A1 zf1zO~m|tJ-szLdX_LT&7maSeo*l7r5vLo(k%+KnpawKDiQi%b^we+~!wG}8DW^Xf> zHOl4F8a;ZGR*H@u-n67=$q@zm%=~r?p=uShNo*cyi~Xa4BD+bqD8yCf}$cbzNHS-X-ZCD-TwV(^)Io5?Q>zD2Y>h4lcH3 zR!WLu&FOJ9vY|&=$Et=wZgS0^1^4gpYuYyhq z6`=+ZMEY-A{#Nj39y!=xwah*MmH2zpZM}-uwzkYE$cR;l#7GGB>-^UvP}9QtxXxtL zbu(r=@c(<8sg;rG$DdXIObov`@Er1i zGYCuH8rZ_QK4Vs7!!N|w@F&Ixtd(ESn}z}qFl%)<`PyT7)YTtaZp-EY0AP#o^WmPR zdCF_)D=I1~Id~{De*4usa(sB1XT`^04%;R!Ygz^Oq#PdW#faGw5m8NEGyE$ez1r}p zt#wf`b7W_AYX_%sn+S)sK~LBboX0mIe!Eb)&@}d4!=x4eT3b0eEg`D3XUsW-;0odx zx{sX=Htj^MaZ9X&{U~X+mo}`cWJ(a__XG;Q>W7q3K7Zkoz0Ay9S$888kma&rV35;c-6c%N6GKTFK*yb><73dA?rTuU*F&S8wFZ(hSTXY3 zJ^1S&(0))OluJDZS@Fk>xxC+#upy(za$LXQMEephOD%5Q5d9OmIH0U>Nn>npuhd8* zal$%u@=u_4{ukN;G5AZiI4taudd3fin@oG8@CD^@zitw*hr3e!Wu7#{kD?P1vc?RU z#b*ahI@9C!`O-$>g^1$t!}j8&1*Ufx**^pf`IM>YKdkX5N+$wzc_!B9~8Et}VQ+ z!L5x$T}%Jo@?(;g*X64J&BWc?>&9EX-+Aj$TU%ShJ^C12MwL?4NoUn4Nk7;k1Erwc zd`gGQUQ{#C5Eh+AiaIa*Fg<5gSeEo{vaO=!>7UX1-UjLeGn~?Rh~0d~;{N1P5o4Tw zmhkov@z)h=zxiCvA;7>-_-U7wi|yI|G<+{^K)3txZ}nuD#xQUt^Jh5J)z+nK&@jD7 zUF)LlgzE{~{pKis-cndu3n8a#q{qM_ndRs1yw!Y~%Y7xRIyygZ`tnIa5SFu}_D<}% zX_9~YKA8Tx{RU(4>Wp1_k%hd@jSL+d|MsN|l()3zT<{ZjznnSur&o179;d077+wpA zgWI=b*d0can1o;sklCURBGN^MO-}7eb+;tI3+C>88E?Sc3wYouPU5`J4Ztk`T zZ8_>gvW4eKW%DwOQzqNZ_0wrjdw5>7ObEC4VLp>dJIM%=d5uL@E5c9vP;%ndjw{2I zq{_$!;s5!k{Z`oh>3WPC$KCHB+ba-#>sP=t;PJ5V?!@$MIR_@nR$zDhtRR-FZUe?! zn{!okzdrW5vb~s6a2ekIm3n*l^fbsFh!;Puo z&l!KKgzpj-q;w^?Rj|C+=ZibL38i`NnG`*sq#z}&scc?vrmXP-<}VoWK3$lPUp`&-TTI5tp+}w z-96t-MV=()``$LvC=6tjmucyK5lZIyrd(3K0^&#Kf5XmHpd%stR*#H!?{nUIaLOI@ zpvEKgnVdBPwrsL3AsDKm3W$iiu%E$Eg+?*N*Elw>39%NIbx96}OVZNtmbSHd8y<5X$K-LnH()S$P3dJ0 zOz>;8OaWPCmgDFyZ|6QmDti|5C4>mgZ8WcW8tUm?wCu!R9*M7Cy<4$Nkm!4|C_06K z$9MNT38wA{dR1AkiK^!4(NRrVd~B;OpPz6>Y9+PM=C@rWLzv@ zg0O$Dlv?DEM)qM$oPWuG0~^D#$NH&v^1A~BpBkEB3&JwsIG$v82Zm`i(Y)Oc1;fou zHIP_z!Ky!(Pr#y$_Gim++5N;INPS%b4=ZUh;yaNZ6KLB)_{M{Y;AKX)uzO6C{z0qNk`V8Ya z2D1v#6RcJzP8e2vZm+RY|rdhGmyoZwRgK z-(|V>qZ31?Rwj|3i6rYQ3*zU4_k2S*qPvNkF48}mp4OfN4|RYMZ+@n_h-drmx0kTM z@fF6-o7>*JK3zCRQhDm>CHpup$K`Av^wYe$OfMvEj!OP+j=M#7M@Pllc^TF1n$>|R z|2&ESbvk|kVv_2U&=N3tvqgHLCF`&3;hXla-ZpWr2YxBwGv8`coa3$P~mto8|{57?pfa5Q@p=% z4+OXGoZ*&;CCC>iVtorH`?Pmh*L@vw%^!fM+IO6Mao7%{aCm9_@>;*)ihqpksv7?M zdC6G7sz({UZ+=e|c)!&v5)KO7V>hi$2spL8n{VzCWaX|>2sZXw`_{A-K@ky-hs;Za zob^mbS|s0I;m}djW7e?wvg*AP7YZJuhZFtD`Z5{!DTNNgyWm(qA=FDM(;Km^Raj`= zTTK*qRmvI=jQ0%|tCnFA%Gd8<%v6$?$PU$(0TVTbIux5;6&QLa3dTs4;?KDJ5QTyF z8O!I)^VeCVo~_E>DG0xDH6u zrEdK(=@X(KLiJCw0tIy)yj#qWb{`@u%%OLeXlJ^t>Lf zpAx_5Fe}<-T!wia{rt-cPG8x9$)bTUi#N<>OZk3)MG{Y$SRDn_4edCP$d~e#bO*nh zgIvS}#c49!N%sI#=maix$BemMjP%inSP}}kLO&;PK^?MOr@9}DX9cS{ck6X}qUQ(B z9Tq|pvv(4tB!?&7UN+v4J3|OIVE|$yci>g5`Ntm79z8xN-4|!Sl@$c^gX|K7Te`ZI zHP01fh6KQqh{RhD5LpH759)#~AWHm85B(z_J?M-RpIv&vevwv>%%mM^& z&!BF!PhW($b?w`NaeulX{siZlHq#Awv4ONhIkT- zYpuH$DywKK?n{UtxN5au*zkWWfa}oGn8{t;W%CGg9Ej|MNj^?gBpJiJ?c;#ap2S*y z*FlaSN?lBrw;B8zw#r~&zqQ#!#<0FVx>o_voyq6xJOnSyQ(C?eV|dJYPZ=kLw+tYE zBzX-^So|+An7PP0M6uNly(2L&MpsC6 z^oRu#!`m-Hr`eO<%F?XQWTK+OJL*lWNT$d@ZTYG$kM8^g%h{KCR5-i8maZEvyC+p> z==~zSI}p54@5-ZlOY}jTY+wIZMQbR2S|dkWEg#`SQh-2e4`P3Z0OAh>Jn}8M6vW^S zuJ)VlwH9s6{erbUv5PPR@Q>Yub6g$qs)ctjWS9^JpZkMR9A*1C?CTJ7Ya%of5nX% z)M2TcpHr2+0VflExxwc#HRoBs1gEt(l_@Gm3eCW=%v|2WUrSfecCcMT<`EOA89yZ=zHtCWA+@IN* z9~_9yK+?p5EPNccxVTudAOIoe_knrUkxgpWpcGt12E|Nvc91BR(lCK)bhjmNa{}m0 ziz#7ZMy#JOUq^e5m=RVqU+;{J7%WsLZ8=_J13IWZKqy`;?HxtiAwH-Mb|y(_O07j^jE zjNd+wd+{rC;}l&ikVqC)lhq=Gx|XyntSV9YeKrn)4dV_{;NQELb4Bzv6)Rf?Sfh=Xf%Fy2W!3zj7TS0Dt_% z4*j<>mzELK5c&Ggvl$bR8wfN;1Tna$-OUUginEk8l)O(e(0Rm7@K$!nUDQ7k`dk~| zsww*G&{A3Iq8Fx>5y)gFr@w%RG%PhWCC0*dcTvd(%XTdL+9rL69~0uGq4^9eTjK}R zAa=e8O5XEZ(Y7C+4BX>_%W^9Lfz!mV@toJky4_-j%0P@Ii!NS8CtV+p)@(DQ=@qB9 z8RucPH*3zVjd7b>M8~f&MT%CmhsE9m+H=VH61WCQXzln7;JA04J;!SotQ66y`%mlJKMQVB75PP4OHvZjPp3Fyhk2nPx)jKt z1W@H7?()C;;D8*kxahlYQ6bnDcL!2$qKQ`tLC-tA{b(&Y^b%TY9)10NpHvwFGQHHFfM}LzWZV28Qb^jZDt)W`O{7k0|ywP-mcDYGx- z7Rf($8U%?hah`o!wW%xrt2n|2A$o@dQc`ZCIIT?l!+U8WVrC(a3F)pNWzV>t52;V; zlAWJ6e$K0&F(<7VPDm|`u3EA0ZBFLt!iCq20 zU!@ZthO6uIIyAjAc?vwcTHf}1)t?HytIrKre&`o|*m zpc1vo2N@Q?JHQDzl#{u*suIz=&#JY-z7>ppHREi9B`tE@*YEsE$R5XSBnciPMWrc5 zlB9E{5j(_Bu*AZ?#r_MmS2=6Ee%=*Z9!k$|cfsOCWwy_Dsl(8}d&ve-NPE&AOeATc zZm{jg>TnEjr zp8UX#7lF|BE%z)Ek=n$@si4=JEtA6m>rFgUV8S2&$CSV!W@)Y#sp}6I0I?sfa&P?2 ziKto34wf?W`mx>%xv#e+y~KUzn^gJ)iPZ_P#DdexC=Qk7_o3qXRL2#9+A!wD9ES>L zw6p`LH0^CEX~zK9AUMiS@bfPCEBcE=UJBs#xVg_-NP=F>1jS*1sXVlf0^zz}Fp`H#8K9uN{EU@SoxEOtDv*WA{55 ztY3*Kv5d}R5%ym$y)A5|BU)+7k_fb;-I3L#KBpk>srm|_@J9&9hYi0!V{uH9h~wDg zASNW+qKXQs{cM(U>5S!0EJ=^5MGBOW(vgcymze1?L9BH{3x`$*=VAZsK7F!B(ZrY;cRKiB}!J)qS0sq$#wn&DGA3SuH38& zIKl3zJd0Mgi!Iit)g4~c@{KV9;i;V$|I&g1u}C}s)=Y*I!MPwany3V#Mw48yxRq(+ zfo((grueHh!p6?gws3ff>CANxiDz+iUd(c!u02 z`gR8#Gbd>s6(yTV{I5fJNVO2S-UnGQ_4&|@l!#HH`#$|7I~M6KTIdue4ezHY#XL-& zX`Vl{s6ZZhXvQo~10J8O)C|{D`sG#l!1YeqMP-O<1nW%mEowZR2iYS!{w$vgw#KY1 zD?V{Gcv6oo$pG!^^+XoU2dRQWm+8EO#hs{lO8^^mqBS(^BJZt3#L#2?iV8~|h*c0( zNT31IX@?iHrbR2iW)vp*6k zfaIuHV)#j;;D+1fQ^ce zhhF=5>fFm?dVCk&5ew#dH2&RA;&+#>+^2BM1D!L%Wn`Fc zgXnZPDoL=cNvAZ;&t*rg|C%z>z!)i^OIe_C;c7B3hlYhk#EWPA^$v*DD5ogl3_Sb za4UYscq~RHOxHkMrUAF_LWfWQ4_3X?jv_lsw2lc-vAwsW>I9v6Tdsy zykb_3;>A$0(762rNa4m4ND)z;=)S|xdK4aHq`jrEv_U9nA*r!4n|lK{fb8KQh$x~9gm{-x_22c=VQZ_mH16ukR0<1 zD;x-QA5Oy+jb1)cRMnSp(2exVa!meY=Y!<+AyII~*f955gK~Lm>Oc4wh*!p&(HKBc z$cM{4uHo}zY9OKr8sO)+Un0t=kvSLc%XMdc7fYsBel;xuAb}NLUFclJFufWO3$@BI z07^O5U$XM6qwc4Y5cK6oOy0`UaY}^xs2)3GFU9|;cCx~j&T%Q&!Yy1&924%?!tQmI zlX@iY@$)$r+EJEbSg~|`U-GUF83AEb!u6Opp4xF&d^piGp-PU0FJd@@B-f(DTWEs` zKNi&1E2W{qkl=5gSMMq9KU3e34V7-numlnDjZn(Z+it-6Q>b!+jVzw)JGUC<)G_NK zUljsdNUo1gNV;z(0SRwP&EhR{Q4izK)~~)=Bcn4)>$!eD195^eKHFcrI)oWX$rLAT zF)x(ck1(T9EyFFNT=S#IpjJlrlI}EXGEdWnw+G(pRf?N`1HeJ&A2aouXEMg;d{QV!#oQzb`S65r?cq^MD2{662F1q z&J&*bO}Z{{eXLEqdl_;m#>KHXLBNg3Nhps+dOJ+Jeb@T@`2Ehph+pb!{Y9nc&Y!|s zbGNo3;%oa&K<9PmVo{)zGWr(Nh*~N?z4W{ovw|0 zh_I|-wANLX$x@5PJ)Xd@lm^-@)zqa#`JqZx@N@&dK6db|cf~&OU$;8LF?+c0@_5L7 zi36@fdU62Cr==+r;|~Hk6%>ydQLL7D5={}TBR{%si!a3^cy9)vcl^Y|e2^NFpM}o% zR1epkqqywz#JdCmgHXCGdD9liP~}fakB1#{;JX*pty|0J?$ksz!w>4K>I0KKKQ!P5Kw9oSbFGJqlssm>h`{zp-Y7h_L2a&6 z`U^Sy>Hw;nm(4=(|F}mekWgBYPod90{PSwtdN^0F z{?Njn!sG!5GdJmMZ|}xGrx1-ITyVr7$sse~hLZJ%-b!K-&FWtwB}W`*-aYiP?)$Ma zC{v=earc?<;)X^lOpLwxk&|sGZGp1Ov?cla=lBaXxRuk*)cvCGaP$A|u=04rGg@?XQq7dte9@1Kx3M6s{fzm0kfC%IIsS^(0Oe3itPregp&sU&2X} zKqVm;4r$G(^zBXvSt#IPJO1=?5|^GO1Qe`5zdFpzw=4g5FV}U;3#5M@x=KJ~#jCXL z5+PDn!KB1BH!dOUvZiMN08p*c--KVu#TRM^edV5l;P&$jZbqiSl=lIDoFXHT zLR>&^JPG=tv^=Fhaf8VB`dA1I2P`yj{0z72k$p zYnv+J<3gaaD2e>1@Vhlu-?s^*|EnJ(}4bWZBkd3fo?c$ z2O)jAHXeU0OP?zWcEIlr+owP=VwyWQv0CY^I=EWreoTiv)@Vi<6J7`pt3M4v3@Jl4 zp~YQBolWSAFe$$iWuexRxJ(#ExZYQe0xjM}y1}B^MC)-uQuUdb$es7Rrdax_Xb|X$fEQ%Jc&~#Pv*thy!&iJjMh!Im#nc zz^OWArr=L+5|AQ&83+e6k3`+#l+<)~&zl*n{g{{Gt~Fu_3jb5v#?|EA(JH|Isht@k z*uhl*TSKk-5mUyh7y3sX#7oZ==*fWjJ9hz7?@+=jot}&IHgFYNYBf{gXSdHT|FY9Q zZ3OlW=#T?Xe4ix@72#y&&A<%QigQ*DNQ;6hP}AlG3Z2TA-Rh(62@F`#o@%%zrDndHtmuZ41=9o$13y-7FkyX5f?2H2hCWZX zqm7p_)m29K$_vB};=V&IXpU-wk8ylR{e=({=DtL{x4|kK{Wnl`q zKAMrQwpC{Y*Y11W`98X;KcAPa+=_NTnW)t{lhQ=7wGoR-zh*GV-;@46m}TJsDR3q5w^C18Fwv2i(W&0)C<4 zXA$;2w z9qwg30J^gA>dD$A{b!tHAUaB}&~l8QmKl(ct8wP$gvumKLbp_05oz?F0wW?85swXE6PH3$E? z0GuT}e0R|0|Gruq{Cq<>+mWb^mZrpR7tC9NJuX}|1ZTGTyhsJay~a2yl9-Wb;wFo{ z7Qb?!PcoTUNa#v0o$AE#`6QKt(zo;eVKv$IAB*HwH15^a@eTo*N}zu-g@wH840e&d zC5IAbgwH@c4H_mygWd0DI@lyQE2{OvO1{}A6a1g)fCZs$wFCHSFHdT02rXEQT{cqMv2z3iLTGoi)?s zJUFi-_|XCoTL)G2e$!^1r~||N^88@gGaEqgN9#~G7+ng%k^UfBT*4OT;w*fU4YMo` zYJ5J{&X5cE5%?>hLZXA_$wH;sI;YlC{WefiDSZkk2)2v)aP8EEIvu;}!}yY;P&$EaEr#5>=(wAT*u@Trz^ zUz$Qqa2j&O->ZuVv^-UQah}KHrS?DD6cs@`Jh5v^PPVR6(5XF0)V^hCn_93AWC>BZ zq$_V<#%3uS#tk0X+*>7Q3Exc4Fcb=24e|Ctn$a zjz@V1y_!XqkP@2Eo&=U2xC6=61iv|5T%_eseynVL2z`E!@c&GZlaQ$j=jkIRw0@y2 zU`i3@hKGk}r855ALUy?X)p?CT_k?1AbsYz_zf$q*y?ug!h0;1?{F->Kqo3n`@-jJ6 ziRQDhV0P+eR;6+s55z;2UXR$%`(J2taY=V`ZP_Q$xhHr3ehGG%kxA0 zT^hN+(1q)O*L^Z_QsY3v)C;NHsHk?jh^?rt{y@NbYFDtoixif^I=HKNt&-RyT5<&% zYuRC;=L7y#x^?jcrc-h9m-(!TJ<4)WlEn0x-tF7z6g$b;*Zt1>{Om*8M?#-sDX?1k zPyVWLuTQ2G$hlucey0lqPk2hEgN7;Fz~4})VydK>r^746yK-?_i#`IT>V1yOu#WM( z)}uv{%oT@{y2gJ-NLm|PO5z*ul5=khQUj2wCE_eY{x~&t(>{%xQZiR0k8=ab_`Y+< zL41VlDZ@wuluh{-e029w+~Er;ONiZV3K{}gRG#xF4rv}!9dOsNGi;vkv!M}`y1%xY z5vI5-C=XE`P(1wha(uY)hYrT^HW)Ud5Su)xp18iGl^!_!(OcbqpY{1nUwF;6H_Pmm z4~Dc=*9K4ST)avKzGH2AM@9`2ox}o$p4Lb2cP|{7NnVD!j|C+X?4w!6Ny=PoXGvRU z6au-xjXQ&rfcim4+}$isALe)NxDp>$O2gvT`m(n5$G>E;4x5VuAtPNR0kYQj5@L~S zD8&>0lYmX~4fVOi^LTfVM%^C0XUH^L%A+B2@t;3M*f@f(#wlUC*GO5_3NcxJ1TT~- z&|i?zq3jPSqx+B!zrSlWRyUFgGt2{_jMe_B}$VdAx&O>mi1M5-WKq{P9s@m-7S+d~RpyX)$vUy@T7y)nca) z8s_60umMo$+f@H9srS`ExJC~Sb+I6PkZd-%IPjZK*99cM5!7xSGUg0s?NWWEQIzAn z9(zd)$`T}`57D9>0wPRPDgdMiHQ@we0Xs)H6oG&rKlb;&y zzjU&KuYoS}g!Ur#Ay_P$Og0m?J5OV)wINkN2U;*;j_f=g1&IG>EQjlOh-i?R6$06y zvnj$a^b=J?JYZ7fgNBRnHFu!E1s&*1>KMsw`1DG8SarsevnMm{6SPrh$i4df61M`Y zRQrxL{yT)#>f8p6b_1q~ZjphI1Ro2Ke)ZzPs2@Y_AyNF-KK+q{aVihig`1!zjKu8i zvfIY*4l~62*aM+WmrgoW=siCD%C(C3c}3 zjFx7lokfh9Q%gw-n1-r8moL7g1x5Cs>87C;k0#87^kok6VLSkl;Wg|i#mysrR$XrI z-56p-!~_}?Nw5;J3Gtit-QO0?TX%V%c!Ch?FU8p{zVOKBB%I@0M?)sPDfR`aA38r{ zZ`c>Joy%XcH9gaWW*^jSCdt}3@)TJz9iA~V(A#^~j15{w04%0Df)+VjobFOQQSYRT_Icn?R_k8^KD2@_EZUFC8<41!2 zfP(r^`$j4k?q#_kZ{$;3EwHEW*1KHiSL2NpB}4!71_~2ptZTK#FZ9HT?r6Fa;H$m3 z&kbeW8@|3z_U9U$|9n;z6(b#7%%b(XrnSf%emLKXtD|5UKaOKo=>c&lG#Ka?53QA% z-3v5O!6!f)h`>+WmPfX+rUA$eC`FNE`?wY>Vg&^E)}fL!!rDj7_a>h-Y#uw-BP_y`R^dr z6SwuWhTj)Z&%KRT!P+j?Wxd)h3<&IsE`%R0PW*-#qSREsMPS#hRdTU+KaWd z`3>1=HN@Zrhz@Vk%)BR(&h#!2M3Ul@UN3wuwgQcBQ{ z)oltJTBY9tMZh~S6Tm0%G%OXi$1T=*oG^Jp5efLKbsr%E(V4eS!$1)KFHtnt8yH7dwF>Ho zzeg+JKYfvPiYC7nM=tEJRbiOQ&t63(iy`M*57Z0<2NleE4^%q93ECU+Dfw_u8Q3bk z#_lm#+KS)gxn%(qNMtu}7#@uuM_2gB7zOQ$`;wwPj2RoB z=hIYO26WqwM!PkPkDkQY_XeaQ2N3QOWHnEgs>#Ah_~_dq&;kW0F@FiEFl7ml&>Nys zf8E#C=PzfnwzP=x9M~18t$6m5^@U|{Mp?gsb0P^#={C@$hRt9tQ_E&nt~KHV++&9h zZ}}efr>8UZZ-V=uV_7)Rm z7lBcf7POGuBtQ)?7|X%9L*7dg2Uw9Ks86pMiO$DfY9@Ws~|7m#12{cT*T& z6XM{OsHn)WbN*S+#ewB!E0p#7aZASuFYT4p2GW&Yubh$<$8Iv?yxYuGj@ghSl;doi zsgJBl)5j}4NsiLXT;#x`?efKR+C?Y4EYB6&>L_Pw-=JJ_*C#RnaD!2;nJB&L$1WNO z+b+04Z@!ef8-Au$nSpwVdGl1;dVr)Xdu-V%qSu6eZA&dIEwc#-S40dwnE_ z>Rxb96Gc{Pm68~hmjA`siF0X_3;^iJ$dO6rc(kes1IS60?LIl1j>YF5#U~|{*or%M zbrIF;x1St^d-ks-tn?`$HvNsTUo5YGOdEl>p8U-Jx?*Eu!D1R1*;(UKM%B6?boU?! zt!vz$%t`5D+!mk9|FePqS#^)JW~;aN{nF=iJmycBPRP-2ytpywi8>Jr)Jdb%#YbjF zp5z5bi)+EbOGiwWi~-}g!!Y_hf&x#9O%GrY?EJZI6`$26j^=3zR)4aE;DJk zV0qkmKE5iGnZ)HATk`*PRA>4!zaS-kI^%>Sc@T+`X2AUAsbbBuae-giAb`3E>40Uh z+oi77G_Erjcz;hVo*&rY9+1Q4EznrvtkWO=)8c`(1Pqp;z(B48@{fBEjtwpT`!`W{ zey-VI*hDX6I=)@oLKQTb>Nz{uytp&fVHueHKuf4TJlHZU@WovXeY9HUGQ;MBfj4k3MsET zB#bkT1|v@aN=F7*?*n1T(b*YJgfBmuk}TGbyYk~G6!SJZk+dYBe1#?(qmBcIEX{1& zjgMg;`83comM7q{yR)ob?y8mOo3ovuv`$$>z_zIFGCIkI!zYRM;dg7ub#2v-E&E37 z#4&eg{M?PXCa&$Bm(Tcq2j_-Mypb37_LG_XWrL+UNCoA8HptQbUThPFlQ}&aNyz9? zvl3&>^V>HSf0R;RHV0(t!;j0dUCPKR#P&Lu-2P0v_@GX5ex1^ zdtuFGB^%eYT6C?P;+`D*>F(}S&MO2#n)jGh)%spPs_lgpv(S=R(CXVRVPw=hS+Yd9pIEzJSSXg^m0(eP z#O&b=eze*hxA&cn79Wx_k@KfZ6 zSu~T1?Op5ymEo^9X`%db!8P{R>P5wb6txPEHOSN)qwk%Uz01TE`*F~;`Lx4mP$5SXTBBzYew_k!DY%pCPw)xj7yUixYX*sOa))BzgH1l>t4|URWmKa+n&^@W%r}T2N(m zw%dJ4B$L2mjb?u&p3t+?<)!JNFa+!n@$6P!uGciG6Sc5L2uvERyn)h zDR^NT@d`FspOon2d{J`M+v9(bRc}%;{UvDJah-F;W{V-;`V*~a3xSon;kT%0fI>b0 zE{-!rty6r4HLpuk5|cA*0{z4v8U0x5hj+ehw7K_KB60`c<-GEVsPm>s7>7RGXNc!@ zw(%tG2~xfK!D&7tN$O!-)lY63RcN1JXxE6Q8V3asi~f3~Ig}&GEXEUH50UcP#{P?J zI&55x=c?P-6^WU|<7W8TNs1n9Gvi|Y2AruM3F?IUbva5=Ms8&CEv`y9X5x;MYqI5y z@CqLAL#Yk}ceHf*8aI{P)*D5xM$*{owFxd^)LGIh+|pgf%UZ8()vN5s>QuejN|}p$ z-!+>n`{_xN6-oURR+69TenLj_LpEH@KRok65g7WhN1swXL7n^PEKd=bgHQ<@Z&uW3 zVO8QBNb-f!{n=#okRwxVOF`tu1qnurIt{7UDRu-G%das0xr+8GK9xCG!hS-5Ed7g` zlM{oBOZ@1T!^l4KYjZYr-@5^^vG*Zr#96(Qsm^C~S5tPOovKA*#BGt56*^@{b=|J4 zHTH8)=Sx{%-{Mp?Ee9Z2NPAu9{7_VUOcPB6>)ou+@EicTzlKzpO(4j7JJUMX+`HcA zO|cikDD?I9RlG$;PU_de&Uxo7~4kfH_6X8gH3Mv-?A*M~L?wJ$vzWCd?u{lJUtKDx0htBIj+>n8Hr z?&g<^&NN>kxxm(agDs-~~a&~|L*skR9Q1SzFLwz;)RX-uZF2biRn%EGnb zKWVDxH5eB{Z^JM@aK;P{j=ryf;@)-^(8ogPaS7>u7q{Q=m{}8e2yw-*RZSkxaN_b| zTSUu$Tb6dvi@Q%{31Fb;rl$!J%caTvb6H5tlcIG8F(s2=NO`nGGsoaN+Zqx-BA^x8 zvwM@YrV_?Z^C$HS(p%4uul;FY_#L7vQ!hS_kxk3c@7#%2SoV{N!&B6RfbvIj1@Y6F zB-a@++kA`+Lsk7@QzPMdgokDJt)0+*^Jg}LxU}_E&T}-b+rM0g{{Ej2`&#QNM+ut} zN_m{V^%Vu}GYe9o{5M`UkBy`-Sfx{%{Y3J9ZS^z7rBt((Q7=Jdxn-43I%etVj~cB$ zvlYFoG=3%PdTcF%itFRXa6*qcURJMZRZFLZU4s8Ul^-UY&44qRk;k$oEBB9Tw!@Y} zLOZZG^(WgE|4=~ie+-GQ$nrR|yq~{!T3sliF|-qe@grLp7X07nT|c;>D5Jm7&3_}r zEV7}C=Qz)|V@H2vG$f#%HPGP^)Z!m|0`Rr7l)A&!rotqpAck;w_8;#R6Gp#?+b3#wDc!SnSS$N@~@fBilkXc9NXpiAjr0Nx82hti{pT6BC; zh+d^mqejP2Rs3MsoJ~^8J9LSI{i9k1Y9Pndqx}!O84vV&O}T!2qj^tS8Gew3kD0FX(Oz$|**_1Mr~Cw*P{t-vuNpLH2Ea zsE(4lPd_G5KNcPL#< ze*yWw0C$3*f*EfOdg2MzdF%H-sA~}W_DM{Ckrn?lNnhWR6|wL)ZSU^>+!7U2tW`8Y zh{_gZH5cmgjUU{aD*X4b*MNB7{pL5;PwWP^M-rF|LC$2lU~e7_bGs`0XZA}PQ0|jo z-D-@$1O^W2k)a9Rd!LgtaqBgvQoly{uk#3kXJZ?gCQ3s)bX=Tzm5EKJA|kEhBSu+S zeTu9pl@|2*1^?QTFbNDR(%;+Ew{MYE$rt73-4ewq4nY%ob&ND;f7{b#`Qoo%-*YGT z3N0Vtg9I~ms*OkMGBZiJo^Cdd0Jg3c$Y8Jw)8R`k1~5B1IQY8(jERe@n0xB+>iY*TND~K`UF$zWJ&K-fEpVB z#Mo#2KS=1pqY|V8V%S%H zF#!^aV$cqtKR`dO2YlXvPJtNeemT5A($(opHm@=M znO_0aY1^-08BsscTl3q?7b=hlz4RO$zBFi(=%7%*O;aXl=!p?~00NA8LqNB|WGIs1 z%qol|*k->s!9Qdqr)aQZndUH439x62N?I<4%};j+khOI=62J`G2Zc>Zg-|H^$UgKuIc4(L zR5i_N0mSmO+es^1m-e1bo>|%$T+Om^lYcCGm*V|pJv<2>Mq_Yq z3b{v=h$l%zC>Gs+01A#^9Or$Y5i9_NtBPe-gGpGVl;ER3%H#d&Gr*oS4+FfaWkmL8TG(E8mMak+JL_|tzR%Jwu$T|a-)5C0uwuz9m$Kg z(6pDA5|K++jeHKq3E@Pbh#{whNNW?pSz++kq z!>B>|hgDo6BBT=$H^(L0-cv1ME7H)M1>VPt$vS{;3T#{FjS-mI+W-g}Hesb;wezPa zg}Z|V^K#3i9JMHKD9XH29I~6_AOFk*NpS;p2 z)$b;{2%(ZRJhp&fuVq%lPKre6(4QOpk|n^e!GYEoQiG@#%Fppo>rfKD6#|JPQF1{iFU{7cJblE_-Xsm+@I;SOUt+`~7tp^Aapv=Vd?uW2WzKQM#aO+;Ci8Jm z#tZ&Bkl9Wfjw$CFd^4NS_BZMpF3Mc+gyL=3LAuwI3+QR_GBjE)_HD{6IUv??kmRp zxI2uV=DC_97gl5dAjvV}oTuaeK#-Ct3nL&r=8psZaVwq7{z3cfLA4FqQOwdoh`&$6 zt=;uWxS|Bb_g+xV+IJHPoh6`jI?-y4C^hAhne!(6_ z2_e0aZQY3AqQ}_JOg;tlahC?lJ7~h?2P~W#@gQIc72a=;Gr->3<-m%DsQpF$eA^tw5q5t~O*q=N_(_e$2 z*T*hq5&Taf8{Gl$k3-4B5tu&0X269qSrAI&UD|{djUSQa( ztIaB`f&7GE+ID~3EL8OA0QqSNI??lSOh@S>=!co$sY8mFQjL+U<&=5zGEV&XTGR$2R|eLy705C@xV zj6lANNU@J;l!9z2qVL}cfg>xLem!cs{xGHXy+wdGIG(dmZ*=43xdWMhx#wkZ7e{I- z3f-{;1{Oa=@RS+{Caz%Ld9dJLH_F2G#`KXvr(mCN5$``VqOfF@3HzJ!jTQv*3%NH^ zjZXk8+VX}vw}xZ*UV^?%DLBv?oF%A4T7+UnR_YF;`p!pkfpL{`{~+2(oP{F6-ejdX zt+$0=j&zPd08)bT4$);>^#al>uwo)!37*)!|>Pe8bqTF*#9&+?q3DC+&{ zDx4{0(ami86H88gx=rVs%=gGS;T}0Tzc|+{{2IP#ljRZQ3$iScM{<8VbjBBRa&jW+ znTErph;;lB|JhLMDqe0ZD5Sjx*+&KL{sYxJ-zN@(h@HxWbD;NxY>?1rvQ=9Xc`sx_ z+H)~UU0i~eRT$+8M{>P>{(|Nd{(76<4*9&37Tj4ETHs27`AISs`-kKvMwQI7z_trk zv~eG`$z4!#RNZpC(ZAlICh)32>9sp4s)~@EUvFf-w>#<^Ka(?S&%o0&E-1t*$kbPY zD7U)hl;gsYO*05GZvI08o`p9Ew!Z8v5JAkFKTN1BAHb6>v=x7zJcU===V~A7+5+S1 z_@(D#5N-p0ooU6*3Tly73xAf#_b(~0UvVXM?LQC75k%a>m&<8fxp(;Vha&F6RGd26 zl&mf1;V!WvGM-gFI`Ju>bL(QhkY5Hp|Q-5ivM;gYB zt=In;{OfP?Nh4+4?RQ8dIMj(3dWIZMbe6nUubVDn!NpzJmDk_;&Pf8IT+@5)c(qNWIh`}2ZBw+Yw_#A zcfA9r^B^R6vOydYfF(4@xL?{4lw|ykNhU5FYtG>mD_OmCQji@{b=`X6QFm0g7+{?G zZQz49qvzdZ22wA;-vxXAb&@kARYYO%%*TnE7XJ{y{uc?X*e98+wkXz>VF~JM{ndBI zIo~ecezzASAx*4_F`+gN|8``WpJwy|u!n4fY(d`ZmR8__7;IB`8a`(B~u?Y2hR4KA=)6~a;PeFK`xA>73w_4KT1ci+# zOso0*kGDkEk)Er3=O?G~qfc_jUDqSr=R+ujTT61{_`e$)^#pQ5ez#CP3NRxAjITdX@aA+>~=C&=UHQ1}qAmN+&KQQ94&~KL!SEnRC|El5SWb zWw6UEjF~*q+JwB&YSWJYJSa>IZAjk#>&ia{6-4+tlbNh+;$I#tYLYB9 zNDQp~{ryVj>2D%R{;c0)S3xeh4A`Jdx*E&>weLxA9PFIX+~T5jJW3&o8uWA|`phC9 zP1Jvzr-f*-wX?Gnlx+SmE2xUY0Y2m&w28a zkXU#Sdu>>ei>Yxth0Z_znZl{>L1w-`8|1uJ2@dx5~~=}|XeLU4z_UQh{UD0L_Ex`1o70u&~Tes9~a zSKKTCSqzPj;Wd@)?=o~$&UoA^dCQEf(Fx7v2Njovu z(?Iaxw+BGhFg9!c*bBzI=Sd0fYar3CMD{%Ob$oujmT|=o>HcA!qWf?P0_BXo%60g6QOe}|I37pC%E z>X7lo4Q|n5h0ZIt{l#3gs2(<&VrLEo;W$+ZY24#wFW=KRFW~uE^a3!q_>8kWw$}a# z_H{UXLc-F*4Ne!LEQWlu)+766+E~VcJ2W8ENyV;RQ6mXE+pbf1W zHgT*pkQBkJZnWb>#M7U7dnIqEtli9Kw_f4INusY#Gw}xA%*Dlk-~3o zZiZ|;e>4`BxmvOtJ@q&Rh7fT7_t~D4FidG;gxj^V^9fASFg*~(Jv{*wFz;$o965F~ z&PVxH%K(KFN_eJ+wR0D~MJQbzoN`o%h}WyECSgFfzVDIK7iZ;X&h6=ZcF=Gs$?1_ULZE*b8@ zcFcSACYob&7f^Ry%&l4hA}5lK3-pK>AtVlpFb5V!W${wj9DJ*`+wH4<8P87_gD>o5 zTmbTY2r3)3rF9DfD}etX(CG=V!{FTo-B!PpLRhWAdGwtE-+xrP827kd#_n+gb-K59 z(Ltz>f_}kn=htV9xaY>)x6o`$HolK92-?RU=VQRxwRRh!w1a$tLdbO&XYYKWKz^Q& zw?8c(XHpj_5&Q@Yo^kuxPEJ)`69 zx^l}prY?O00Se|8Z=VZY7#nhFDoiN%GgzZ_;>*ZScXmydo^18J*@rA2ut#ucF zGucyLb32JUqy4PxazKZ!Id^6!th}6I2paB5H;}OIi^5YdReHth>33`X#0j`#+ioE9djbLl?^ZD7NkOXT0x+W4JV1+-3BZ& z;N;XAKDgyT^8|hX&G!JvQNER|R@?s&$_9@rWH!t)i|D1FDG)7+&5Q*X)?MK3yKcBj z(Zd*$(!B}FU9P<R&e8pqwnAWG1@HD3C}8|7jVZA zxa;$<1UCGPo_kDKqHq` zbXy(C_jEI6b^IBBY!Voe%9ys2^pSAeErA}~*&p0K$JULGhHu0@kl&;-G6%CaWX*X` z)B9*P-%{a344N&XylX=KJLqnNG%n_zaNW^hbbQ*#XAGi;a?bRPVIf54r?;;IQLGCX0~jNh$UeeTBAMm&!NxlkLHi6u(?|nQ~K5(#=9Qk)s6jxj6&Un!0izI<3wZ3C@@3n z$!@!gzs-A{chqN+t#7zh8$}D%6T%Tx7Rdd{=;`UQq_EbW=33vW~Xg z{M#pD95bAngXA-90S+o{6b=#2YiA$T2h|J42X_WsN#f2y!H)GvG9z34ab41mzAI+c zrxU2)dwCl`Y0D}Uz(|sH;{V!vTp*=^Z9HKhi<&mTxr=8D9^|W%HQgB!_>2V3dHD9g z>c5XwS4<+~SjPdA2kdHwDnCE&mb5TLx;5&;vepyL@e^L!k+|>b z9(dJ1VYZB-7aSX1EK!sz^9bY9Ohi!=yUzSN)Y)E_Bd~XGZv*;trCb?eqkh(=@Xpa~JwwBl)geAWC!*grsP{;l2QY>bj&1)kY( zuNjUEn>uFepqik%YA-JG3~V0(MIdhoL{dOSwI@FssbhMFV1})ADhIl^F{#}J?ul=U zKwcvGL-?64V%9gc&yHsEbhW&&?9ilzO9>94939CUn5Vc-$6f4<#JKv~8W_W2aglGD zqE1dVwrL|w#CTr3HGH&@)R_Y@?1urVZ-Ok*)u3PO>FV*3(I&G}%RUKFx6!Xtri zH)ezd&%Lv8lxy&Mo2Ugp0D3d&q%nUnymz3$p7Nvj*QhMNoy4762*rcG1lRUn2%+B) zXcB&Y-Hc6tX3n3&K8oT6z`~H~6NY06W-$)5U6xw=uPe!-aiKcXe-eb(#}MWUazyL6 z-qq%DGc%LT24wWX7t1wKQ zbZ7iMvgmt0VblF?gAw8$|My4~kr&)>=&QE+h4R~@!inNCwat;X1x`{DJ;#)uyjNobltyFhJ@CV^#7_3*MXke+H7V9VCU9Sr^RLU&H@u_*& z5#bc70}`;7$D z3m8p`>EfT*lua}Om7_&olfy<*4&0Ly--?rDYPoxNH-00A7q%m-U_ABhjgGC!csw-L zEhimF=V8tXuSBV2%Tv?=1RDgLJ?F9NjVQfus8Uhn%;(skKK%On8>dqIELbhhfi#k~ zgeF*v3mV=n7$~{qda0GpElD#oc?ID`wMphc_yltQu-e&; zy_HAU*ei7GWWu3#(44BENQ(k;&!Tz3=_qL(rjWb(a;p+s6oWq5;v_i22;&<^fO>Qr zvI%0Hf1j4~4P;`UBKfrdLv-8WxZ<-Xjft@?#e(GhxJZst)%JLOgk!%BWpYyFr5+jX zE>xOA>zO6o2NBGKu_#B_K`kt)>K!8Tfr&G?;ZvVnxe;@It9B1-iEbm zj>l5axVdNlGNBL&=H28%$D}mdb|Xq#d&bEP`v5g8J9>{U^@sCHbmD1XKUMfT3K!0n z9O|up;#ny-Rg_nZC;N)lz!^WjIHYe0nVqaq?u@e{WcvMpd6sENO~%KbxspS!iDflt z51|xWM&Z}+PNtQrd?{xWsr|i!@1G`#gdxoS*gj zn!*Go=C~xim|#CvN!VUr*o4Ui6)QVZ8pbhwCjE+HQEbNzI-Ji;9C;hGI&Utsw9`4& zPCSBKQIB+q*^bI~#FN!Xk^>@s&u@|3`-qz}*^SJ8$jW;lit9EqKv~9|mWVT*93JU) z6?m>V7W4KL>{08NHpSkLPE&LITsqnhqwhglJM+eHYc3PH;hn37VslT?Hz_^oJKn#p zGgGb(G}nT>^P?f>p{vjWiQGX2tgo)pDt1vwf60qezZnP_zQDmOJC$hc;1~4Pr;Sbz zSo8IP#X-`DB=uHC68ep-QqFBX=Dq$-gt92?Bf-~X*>4D>W>XC%Fl3nT9pyAk_(Bm1 zO%&uDoGH0mLOkQCLlH*h=uMzySBC#MT21A7+?^&ge7j= zn0}@$MPBrn6e;m+D89KWAk7z!i8jAdzb8_G^?!fbV8^#Gs`Ax-P`*;_^*N%R6e%M2 zeU8?rRU4e>faNy@PEQIk+K7UP&WP_qGRAt_jH{N;H28ltFSMJ5@ZI0$mkEBuGVS-WP^Vy&r35V%{(PpA@DK!Y<-=l)WM{rqLMn zQ-~0pUZ0l5l`NCeg(}8y1ZD(sdbqT{RMsy!=J57(mRh1^v#m=Ek6&EmZb&mDX0r%B zW8ATKi?0~#-gEnk5p9J;OVq$K@Zg^l;{44Ck!^W}7Fv&l?4m%b=ZBJ%MavZp6ZVSC zZ9^n=ZYdHi$B%1(Xp~hH^E%8G*K|V|8g?K0nt~+>+DFpUIY1(Kqm`hA%P+-TC3QY! zyZ7*qi~j@vad5%c?&$82D_OtJY(nRcAAP7Nqs2YC=6;?2{+WkX5O*EVDQ>D?sry$8Gw%KnH~H_~$bW#NTQs$ftRqdZxoz7?LLu=RS+65j+NkRWwXSUT6XfzY zRASsh-Qm;_Ad-4gF$%juwr>Ea_s($urDUN7j-4lkNb%1bI7|JOL_T2$ab){!QLZ^iED z?_ymxT(R_qaQ>h?0BT44AXL-fmTX^7s@jC?TxT{i{k~{pI%ZBHC26;9j`8=pOy{rl zzPFqLuB0Tp%ay=eB-J7(ZFf4x6@^^G%CxT-H%=5kJ2fNs9fuzu=}pp~BvW(Jq~etl}^QI$MV zXpS`uvamCZK{3Y`FZ0^wQ_Ukb%#*uh6#ygmCgFdtXo7}SzoG79% zl)?guZ%9(0$fH_gH!|bX$rc2rVjeA+UejjANq-39gK@6LMJa_K6Yz`Nb;4lZ*mdG# zQ%1?d(^BadsDn_2WPg|Ja45}U6CsE0cizuMTC0v?^a%uH;rxIP6NTF)Ctcx(0*x|n z_dT2o9z(c_2_db5Fy!e^bg9T63KL{!WHEntjd|fazr2dT&YDNhB;tWidfXM`TZn(W z7{nKj`dAeVA1${_Ve67wEWQcfm9ddRJ!<_<5t}NHgqGpY80jK}F=q5<0;(bGi{JJn zg$B6MGhc++U6pD`;9_7!6pTquRjPU+Ce)IYC~II3+c}PECI!t<_IzcLKgx$NEsCR4 zw2GtnJ$qkp$!t&*u_eX*%!fEU<9&WO_mw_nwl6BaJEM?)BNsa#*r#NdN2Egr|W&nSM|FUldE&&DUbKZ}bd zSR?qNpyYO216GRd_oQ+{L*U-WR~{H!XJ;W%bLtbiVMC)rVL-*wi!1N7UgJrU_{I0s zue@c8k%k~8`17oOkZd!^ai8j@Ni*uP+KLQhn*Mxn&xHrCuTC+1s9#=x$-@=ByuOkl zE%=XoC%6B9^h^J*9`NA8Wkab}YgnGgF#j`gZq7h#wOWx7a|l0cw0A`6N@Y**)?TQ1 z!QBX4$9IIFpCL3OZ9-zx58VRre7G^|nQVnxqAot)_A7~v-?<(3Bpd$cntwryejTQW zdD1G5>>Zw5Ke~_Q`lbDrCU(ruW1+yzBzkcD=979mTfp9ZH$LXa-49zxZ-yp3tmi#` z`A-fCzy1^KW&USVM3qw%T*)8F9)jsFj1~)e4({eT zNTNiuF`9S>Gx4>|9!HKWE>HNgdhpi4lONd9J6-GwzZG`&TM2O3y?3j#IKJjnwsIh? zH8j!1L>}ni0$Sa#3|{+~y}L0Q5Uh{R&^pZTb*-B^udkc^6IedGR)FJixu~6RGp-2$ zLux-4+tPOh_eUA7rNHUk4UZD21Q0z3)utE--?yb@mvpku>M|i5q{6o*Sow5!o~ZfpM=mTHGnxuQ?Hqg zw-u7h*;i9{dqbsvxr#f;yfvRP-R4O-tllUh1?yhkjHfuREVI0+_58T$e`m42s#bdv zMZG;*dS7Pwv$=`cG18xyBM-u%A%ER-wWYNrNaF-;kK#GR`IeuGpX*Fs{{!$U{~jNB?hcZon@P|xm(;Y zWkKj8G76HZ27*p6zPD*iT&<@v5^30AS1H$*W zx_j@YY1I{omnTIi&;55Z^tboDM|<|hkEJf>(+Fz~t_2=99>@E8uJ0#?T`Qf;Tb(u0 z->NssB6~f2E~0Xqn-bZ->}OYeuf_k|*jNki2esF9EoMGbC3SpOyVy0gmliz`#}wGs zSYNy_^S;>FGdVl5XK3W&nyEJG?x>6BVrjUP$;0bqc+j%5lHZhBDu~!=w<$sfNKfL& zU^l8)%Rygm^KllL4u7+PB@Rz2?i&AicNLs|rr6EGb+s2GfpB>-Y*}ME``UxsEtkk# zQ=MUHVuVMlQkc}i+0L(LRI_lAll2ShShZy}f4WYq=Vz|V#|P!*i-oVlb7*;^*5=sH zOZ$c)W}PuS(^b+g(6HNIH_S5cJjcb7TixxlB)5+)srT0K)f!ey2RL_%-?&z}p-QW+=_VX;iNsyf8c#gA&zzhlZ( zl(1CI_rd110t58RF!E=zL|K`v61sN#AYJ;!`HJP zm*2XXy{45Myl%Nl7oAj4Wyg=7f;OnoEop#^##uXThN<01#?M@i_q}`f5$Wtn@8>8j z`b(7?{g}OKS#wbot_gXIreVpKPa030xyJPmMhKey_wpza_9LvR%x+4y%#`a}tW2~% zZ+*rXs<}S3IBMHE@f5oh3^keh{P@W-Va>2ChCqYPfs9ifBa8FidaW_9ci2U7= zwv94g%nJ?>&z~1EU z?n#q;tel(d^|b6>$8&ZI6pnuM-$_v_&0k~*LxbgipS_^Sr3<~Mzg_1WqaYCnl6GFpr0rKjjqWvzQD~JNuR*f2^5Vd921G z(TqZy^zwV&2N9>5^5SqVWV5*+Qu~U<7FBiHjWg?qu1^8mR;2kvkT3^zbq)@HPGws; zY`vc*i*t_;RulxhIhHQJI1z?Th0~dt9gTP_xREXRJD?lUAY4By&9aqcVc%)SWJWK# zv9E0{D!iA0BYjaJJ$?1EJsPh%7HL#fw53&jEssnq*YV<;X3$izUa>9ZWG*>${F<-# z=J9Er?(X^&*Yz^tb|9updsb6XmVpvZF@x8&mHL5QsB61qqP)1iQ0oi=@6jd_L&(gv z?zWQ+9nO*sc@bBQ0_#$8^3RN^n;!C`Eq0RX$rk7uUI1;rCzP#M2=&Y zwInNpXuk}(cUZn%rl&|)JW6X-W?hIX%l^UOf+M_Ea<6m8ITqaWt5526 z@=8yTpQ2AVi;7o<2~9vKM)FERSU{nvw-&=~c(u5`v9Y22xA0M)U^$_{@))hwWuKE8& zUiQSEXAmy-8%Z3!FBd>hpyu`Z<)8G=>bnIgnMj8LpU#u*uy(~pcR8!wQ5rYe*B8JzL}b8+uI8pIkdrs-FM!cuxZ$48fuve}27g1vrN$@YuY3?i><~pN2Tpw4Kfx zh1b)=hc-qEip|uzMwfFV%cTZcpz5v^O(s%x;rxTs@h~wfD@)@K5AkH4l-*9YM9e$v zOXp8185tRiStnF46EP(6l?PT?+oP6Rxh%DCvF0bI;Q$6EjnZKj?6gv;TA^&VC_Fqo zXZg{WG)_f-1nf3ipZ)P{F&3{U_vvzN?Wd>w=laSFDw*`DzgvTfWf~lqv?`}rk?7#u z;4!X3bk_OXLTot;3yXMVrh1F{to|6PX7!{`hD#nwA6MEunu~dz_9jH=)a!;8&|fS< zBM+_!doG#9oY~{f{%E0g(7za*xELt^o+(c9JwM2UKf4E#07Tq%&lT`!ut=@e?BVfX zw%loPzR@mUPft$)NKGl#+uPbSCJW4JrS`EWxV%F`1 zx;$D`cG#b?y(Z+e7YC2c1Mt|aO5ic6cfnJ(v6WW0IG_MLT_7t2KK`ns^V99PxV){X zuTT8CnP&&|iYOM!Qh=s|gEBpH#a++GyF#Pk)=3Pit(h_VP2DUKy1bUI0jie688^ zQac^oLVGFnobh~>A%NtRYy2!$uP-wn7s`NFQ9ZMx+-=h-qXJ=<$f+1=QG4Y0g*0`*e%ax=b0(v=t^bP4! zZSJ>A?2!Z!^?V zr!Oq>%t`xm8NO9Rha&Qk&z$lwVf{8pXWU-@$0N5q_dev)H zk=Js?U?i1eLt9^97@}N}!-Ez>4P~jubkb$GytYnVeSU5`9S-hgHd z#l&~JsESsZMa7BFo@q>NB37TJPMXXDX zrhEnp17V8NjPkyF<_grN!HrYSu*YP1#y#e;vZArru*HxoZ@fin;?x*UXn$LAAacpb) zg&YZX`qQJab(XqQYN>Ro3m@@{iSV@-t493(_*qU|%~vStXs6h^j)V@2)y|kV(}w#i z;%9qcS=1WgYYT##L!*#>@B(~I1v%;zno9bk&mizFz1t&Nv0{-V}gsQC9#sue}9 znOmxpq*1>Y>3VWI$ZENXW!{d?U9Et3F>u%?x{{+%g2j4eY57OhY2wA42j=X#<)hSI zDhw2qfyv^|H!C?e2D&g{4cin(3SkN}JxyW8=*5S{w~x717b&tJGdtSft4C zT*jIcvMMEcKAiQU*P7ll8o%uONgYpZwJd5STw{6Zl#lq=-yG(l6cJdlaWl z$4FUP-4%OYL&E$n4{)P*FRjEXpvO*fuyQYXoZUWKpfs>(EAoK(Q5L{$y~3?5ane8QP!t$aFm+1)?&g|%-KjZPKCRzYbo&e)FE__ncB>g% z%4Pu-d*h>ywEQ7XHeM{r(&c$I&m$um$eociu5mky*Ho138N7R?OD`KdcFGo^cJJ2K zan+lmndYN7v!aob0CRx2VPo5w=yW9KwX6oH^9=9b!IkdluceDknx#RQ< z`m;MVGukO`9QM0k0m{y;NVB=F88LLYzeZ_>h{x5r?!vm)p!f`c?GlcY^MLu=UK?L5 zg{YzGhR)=pE-D`SpC8W+e?&Y!sLPm9SNOE z#jo1@g>|kMfw?M1!^|mq0sVxO%E3O0R58=FsqJrS6=0o37eA@O)eL5h$t{!xFH~PueIBeEL~&9$lXd5f0Islfd~}eX>$waqboOlul8amT~vptVZFgctP?l=le4I+?(b% zCH!|HVqyosgV966!+9Q`wXY80;o!c0{fhF;0F25R3Y?~bFJhUFQ_@r3D=H5;hLxW4 zo?mH%+vDEcr>ee1B42H_K;D?TjO1&7mUzGq>2y!7RY)%FrXMI%i*iB^4+6nc2N9)-lOw^n= zBJEM|Jp0RbM{VL*@m0`)` z2{rDb+Yy%gPJf@>B=Zy$=rCfb6(s|a2qmw;Bdg+NeQnUG#N@ei! z^1^Pg=w1k`in`xUu{HxyVZs(io#SftW4ldV?_~8`aCQS;HLuYg>caD$^k>II>*Zf4 zre`(htMUF*ud{PJxN<89C#I}(`Fh{$^bd!W&L)e*(Z2@JIgdQVD)DHtJD?RufA?Db za-7#m%Pgi=(Q{JIPIhAkOg!$-|Wmil>^^+eGlT?jFM%y z!FakR;JXz|)mYfl0iIgn{u*Fo-9e&r%;NaeWWTpQa?}%!&tmh3KaNhFRrR2umP5Hz zZCbNk!Pw`BZPh*d>S(do%L*XBnVh_gB<^s(42+JB);^{mg{Dw2fb@n}t zMGth&7 zD|?rQ>n!zooEdEguciv+HKS@!EbMqJy|9iCFK^FxoH`CbXUr4`OP6eOx_#V7(|K5c zPA~S43=cpWVnsW)sPbt*a1UGCeQo42Kf`lh%W`dcJ9mG`N5S#1Ct|$Kq7S4h4;&SC zO{SCYc+P&K(-+7jGxvwnd_c&%qU^LA<=Ih-qO0lo{hOlb@50VFM2klf3J%WhvD;DY z?8N|0d4bFMwv}$l-Q~gmV(-19n%us>!E0Ag6cJDmP!vI`i1a21N=HiQMWmO2bm?8B zi*)H70)(1SLXj@LLrCboh29}BhkNgLX5M#Z)|&GE)~q#a{***`p7T6spS?e2Z`6s< z@sfaQgU~ZUuaSvon#^sO?19hc@*wg)G4DH$C(|6~E^SKu>0m7IrHNltf)h1TDGV!6 zjD#?|YS?#s{|ZA$X>2Y}*40sV^rpT;*exr9y44EaZUWL`XKfHjj=?{*W2M{D#DjLh zd|XtKpmtPr?5{wP%~6i&61?Ld@agzK5khcY*10K?9Y%qr4?0K zmid~*{0g(`aWqfv=j&T>Vj<(OzStR;4l18!;Sur$x3z>(r{bNZJTzRZvj3XFBrlTf z_L>`FbKPYFcWQ}6%7TKmG;boQu+u^$D~cMd;;MpzY{vv{@eGq8x-AiY!m&@0yz8rM z`$nLH+`X6)19p2E$ea&P@~MU~&Tf~wMKk>bQIWw2UknR4Z(tXdT(fLQA>&B7)udQY z(FmPElmZs%Cr3kA0AiywSNSWwC#5S%kiq-N`3c~N2Vq*pRf2OEX5p|t7H6W_97rm? zo9T%-r!c=J_s2W_*4?}Edul9b_4p#Tj9;!t+m*d0LoLB2>?fkImr7Z|Cvj!hcwd^w zA&b@MFpSf+2OSzn7Bs6?#j8H1wX=+T3Ui3Tq`d^rF>m;|+YO|U<1X>Lgam}0WGWo* zjJjjG+S%N}e*Hp0I#g!x9$Ogk{wuSF4s2+9*IVMHq?N=T?q$$oHjo}yAXiEdy4aY9!)9x!;pI`x7mkM7??qFIkFa1T zyd9>^$)YosSnwN4_s{$x+CM!Wu;Fp|Ecd;BuEfh_|B?H`(e*!IDW{8qGP?2lQmLJe zx(!lMENS}C1TK1;mf%O0Lb-@bz^~A;1+74O%B8;#(IT``RMD1}eZO#BgQsL)m(r&T zSGJPO@;p*OMYasKa)*0t3gb%%5C+jG#I%lyjtM&gsinW6oh_I6Q_vmBcE`>rHLJJx zqv{Znarq~mG{{BoHVa$ojcQ~RP@xxoYaqrOQo7`2d2|n5)j9F5J}}6c5~`c=-?LdG zFghBf1Q{WQ5rI+CkCh94Rhg|Xr#KHR51Gz3n!SGq!|IIg5b+ON!Z=3IGUzkd)uA_& z_+d+ulNLOHRexI4!m9{wTa#vd&9JK=DN5igFUhkmKXtPm)Z@!Xa~~=D7!Y0T9QBq$g}_yA`a6x z9j`*1n8v7Y6?2V6E+8=MSkVv2S3g-EMk;c?5_FwKMwz?iOXYE#)PBr2#At+&bnhX| zQVM=r*t)Y_%_IBe+iIq(j5eME0bZ&sutabX6hG3oNl;OhX(St$#Z!ip;O7ZUYuMz% z@eyXrnMJv1dNS&vUW4aZLIk$jpyksp%4A+#-Ds(#yO(0O zRzP9q3Sk}}iLx8F;j0Xz9VNT2g~b}rV8{!cA~P8gZu>bISwWRiULPFbD%y7kRP9TT zK&x#t+jj+KhCvjg4N_bOy$ksmQRx=e(a*NT(5R7Xgk(83^X-=6x>$d|u|b$07n$ZD zm{&Yu4NX(AFMDE!l?W&}Gq3-%@cme2zl(uT&7qPCl@O}UXV~?N6OK?fUV!K@0E>5C zJc-#!4LB*ZN&7K502B`s*#2{EG>>K5Kvw|GTgqFrucN_JYF1IuZZRZB8RRFZc?qpz ziQF-ZvFD}KeAqrw2(VU^^vH9AjdDl_)X?B0Sp5?y7t1u4+G-h!{#w<99=eWhsW(p| z6T?+(upZ8#7a%41b+A%%HzPHS8^*+Ry*Q3@l!g3AwIWnhqUwK`nIT5DoC|tTX=cm< zn6AsPE^dT$p4w7bN20*tlutmCc|k1~%@BqcSCs$|O8Zo%>AhDhr)qxP8eS}$)w})D z@SkS3QW5Z__(5Q2(j`y8*>jN*sv_$m4>2AEv|r)S46+AMS7go)$ZHk`OtmD|$cVW! zf`ah9LoQ8xhxrH(VkMI*2**Dy^*gQ&mc5@e8uOQfpjNzeK8Hv@#(~8`<2%B9M#HeL z!Qj2d50nFLMQ1TD_yp}X{23bMgt802W^>Y64cf9;CJ)Oc#pUD6P5RPIyZ!fz&mHr} zM-J#fV*3|ss6}?kvGWV^?-1X7DO(Ycq<2xetOGj1qFn9d(UXECR&i>XGlBS047_l# zO0`AQ>@1CM*u}F1v9!V{p#tgZT$Rva%!irl4XK=5wETcq%(jk>#@ulz{g_nLV0J#K z=80s3R6GWm`eq5?FBbvd;mKW-VeNLMx4+o8A7edxlzCYAlLS(g=HnT#C6hmeyHwQ? z@%SV;g%IbLus%+L{hf};z?IDQh2NO!M%%>Xz>egusJ*Tj#KsbH{(Tt`ldJtxe(4~7 zNkb_9=Zeahx$L+^-!r-7rHb_s=HWNDK4n>{Oss8%ML(FsLoMrJ{;rvC8 zVW-(4A9EoC8Bpl~;UC*~%F=C^nh`6hr*zUxz&+!xvl4~bzj!iQw_?)+WsINpm;VX( z>u6|}Uivt~U-rB#nxG)DP%)lN0!yA%i`|wjOSjXe%2CtxgPY}hgY#S3<=zE8^_P|$ zfIGa{@-_aHb$q(YZJN5t$hqgJ#%($)H6M6ewYT`oQL`9Ri||`|pY0`yB-(ar4TU4= zNJW#gQ%gU^cwNU#_~ylROl^yQ?D|{_%PzcZCd~3h1BCh20Gs*oc7(&7fe35s^)0|9 z&fg`l=_&paZzseUb+LGV#gKTfh|dtl)TWr$55VV5V!AiG^!FsunD{pd_y4&*OK^P( z4L?llPKFUuxl!Dvujo=Pkg5tTVr9W6rb{wRzV|==eJATTVbr2GFG$lOlTN2|XT*ym^qK*DCcZ`~CB^7h$>;KA-h6l>6IKw#+buBlR)Ll;H{ zyAamsZ;G$l+d3BlvI~&W--V79i4+$X1IavUp9Wo+DIK%a)D{tk)V)}hxSnKNXKUzq ziMZZL!vhUIWh~OlHWl`@c!m*DRaRoyk;M|vZ9Wf+3JeJ7Z=dfVom$M6iehRFb2>pn zF$k9!LL)lqNaZ%gOf80>fPlWLy;agkj_lB6p49XY&megYR0ZlaQb*ehN^vEI+N-V;Iz(AlBF$=`{sv-F|n{Ta6~l*k^zT9*U4C`MA4R8*c8domkXjVVR3 zk2QZ(^0iVQ4S1;f5s*Uizgmkw4(*M6sWezFuN%drtMh?2Z0Y0SQ}Qz+8ljBu&xp6K zBypNYpB?IdBOv<&hMx?6f40&$>pYaNuGGiQ{)^ifiQGV^PNlr{`xXsBtZtZ#*Wn4)|yYbHfDBB5mewemQt!();@w zcV3ak$8ms?(1wY@6lPo2w+y9YUOsu^Z&_0imY1gS1-}y1gRp6q;xr##%ct)UT`ZaJ z&~gFOKU^`8_WTxX=|3DKLZB<0iCk5UnYN{6Y-DAWR2U>8+uaW>&3oi4c?n z6?wG>m9P!~7Xt6XUOah{U1f)Z13a#EQngr-j(ekAZrs@nz!0Z+q!r-~cu8#_Mue4+ zJjmbi!|GX%^V=^HMN%=Wks3AG|Iq^AuFq^NF2ejy_Wd$>Uzt0G@HvSZioVlEtkn4iDpn21<1s(+rdP(>otOmMK39e|N^%+NX3ryLe^I(bVPYOLB>!Ke6B!}#w(L9$$-k!W;bZB_2f=h-)wV{Ge>xJJrk zJj=Md=raej8FtywgQBj-9VLg;^?rwJ!Vt*3U=#}iF=2Z@>S)QJrcGdU6 zrTuOOoAGKQQK>tla>aL@uc;n^^<88ir2_owwn^K~4>zYRIj7(GH)yZs_YAfv*_}2? z3U2m7;hbosJ|R|Nea99PEmDw&i z?JSPuDi#0YH%6wVrz@AQLtr}TS&S-LImE(5j)c$E^VU`%Ok+|t<8Tyfmrr{He>qGU zo(5`nnC1a>fJ%LVYF#br#c~*+PLC3izZKNfV%ur>li(zzQyXmOe|gBpZpQDgO%!k2f>Yh8se*v;Rho`Gg$CA67-#VJ>Vj^_Tv4X{{77P)c1 zVqkD*f39CpCTO*iiNCRL4%oG=1N| zwT}tKR9J)IhNq3=2faRbbL~uWTtY*7$e<;|GxHtM42&xo{7EM?U*7^DK%e(D4-{_+ z_kOhkr`e$LVd|!GPn3L5Qq340l=;DhQlz5Hkl#LTSNZ~pN;UTWXcQpeu>G0(;(hg$ z)`Cw(5`I`*5uKxEOH2Ek?fD<8+O**&e1*k6gNQ%PP3zTxkh?NM_YC>6!(HY_sfvM~n~yPS9+lF0-mC>qbJ(PHFGNEBrB%%`GivO9zvA#yzW$ayi){I7E9K z6t6j~> zI(EfPNuG-5>yuH>i+rms;sxwO7^S^Zp-y{JVmS*Js~ix044xIeN(3iRT3BnX$)WY( zW{^;5=jY@$myJrzE7z+td`|8z{W9mvQObt1R@WX(psF$**{Jy41^On)Shc3Q8?!PMvdO%fb+QR*fSb_X-KsvX z_u$+;sV8@P9B0@RCTupGFAP9zW7z}&S*sd6{A_0-p5kEj>bPxBjYhGJ--O#DPRvEK z;*-}&gW>FgEV-*|Zlaa2urMcdLKI{=ec(s#k1yWMS0L527;1-H2$h^C>>{M18Rs1= zMOL@yla$xBD&LsSG#OmMlyBIbSOOIZ+bl5(gnTH~jejUt`&}Zu z=KZ5}r{ZrFhLpPP;i1?yJIPlSl;Cp<_XI{EX-ujm$`VV)$%%v&&j#F+00PsYA%g z_=4RFgN^L2xUz#5SgESa+=0BY@90t?Q*O6>A9Ta3F&i(byz5JzBQuWr!`Nj!N77y7Z&Dhyl+a!E3*+r%9^!5AH%y;$!vfNBFn@?*F zXLi~aijk&Rm8bRfzuru9?`@o?nTHR?-P=1EeA%ANRtK*=UJ)yFa+}Iy)T$`5#5tk} zSsUFCbJ;oN*@yU} z;KxVljM0TD@h%7U^24ivTTys~VJFz#V>JHR~wsxi&kR(#er zDPzWwJ2)=;smdo|APEFKoKY20{{s|V(HDa6akAyyUSx+;#8NNwx>L?>&9;u?#e*IU zUAcRf3=*p!CacJM!vI25E_A;Fo;MfZ;^chlC^JZzqRp3j_1e0-P#ZPr4c7>BrOQ{9 zD-{hLbr-v}wKQ>&k|g%BC+7F5HiDPy@>IGoj7rEg-Z~mdgyqoti-g&uW;boZ?fe}i zPlL0M1CHCQW4j5MsT5V6M@wMTZnlidhEREqGhzj%T>Saeb}i^`x=X1L6JL=F&%BeA;g=?P%M z_&18Yw%1qE<%NPK;l+VTe)949SU{eMVOe#`V!wr*O4f^rtWSR?=TIWfo2mW-ds*3w zhlQ(sjrhl#?H%p$+*WBjpWg#AhcFj!iE4BcnaWc>JDDt8jW4Y02V#Z6Oz9D^!d$K5 zpWldRh&?Q2OyXX{w6jAA!&Jl%Aamyl!nz;AsFX%5$7hmVST{Z>B27jBFZIT#(`0XH zqS^0^Rl6$J&EGtd&8k+c2g!DKjf~hDNax8|G+z)5te<*tOBjlFn9cPFw|emI^qvc* zQIDg{06*+J)0REcW2><^ZLx^0v7(c%O4c0H0$OzH3x#KO!0=?y6vFGu9_T9d^7Zz2 zzvy+d&@ft@?6UZ!~ z9%LHTo}Je^ydEFv2lu`7+&J{{x{&R-{Ro}2Ll*_-cn=hdq{GT73ZK7`^78VkTCBZs zU$FlmT2mWhDeb+FE|uKa%AWVvo9qyN^1Dk!u3~8*@w}n~pYYmAu|#$9%dBibcZhsB zd|Vq+#cnd!35sYJy5U1)CXRymr@|v zn8z1?pB~Oi$R_cz2xVaGy>R!rqw6-V8Q~pNj-3brfXCH1mdf3(B zyHRb|tK7#m4oY=uoR|4-n&Visa=yQiPngnRfj$PC(fWYX0?jbGqog4Vdgo;4CD0kh z^d8Lw^=SF^sA$RZgmEkx}*5pgyj93b8>Rt=vqy;VkGiZa)0IXEnA0ou&%`L;Z(x+BI>4(8ukb}wTFS%n8dc6!j<68SP>sM^W49B-A!^gT7>f}Ij{XX=t&rPL3+ja9tDky#wtI7>+RiHZC?W7&!D-K`B@WW*>Zl$`w6PyE{ItH-mzn$3sYq6!)L#2 zGt3)gT1+;#>TEZV=0|9MAb7BxS6DaHOY?2@?1TnrsFQ*K^j@V(DtjNpN(P7kGJNsy z3OM0}N4ppUT3>&}mGZ`gP;y)ED6?3wY9f_S_WdiR%tgs(@I^<32f~{vFXZvscLjGn zFdm=kj_VFZt8}e~KjD4LygeGd~p?)3wCEs?bHD7F^2 z#*!8Hl82`W%96>|AN2Iqrkx*p;a=FWlU-JDiuuU;%H%mOi%zwKM`!FhEObN*`?Sxt z`v70mGwG}Ap_JR7sXfp2^hC6A;Vkr#phgfG>lc=0W6gwi#&H_=!&*j2euh;Y5Fx{ij`u+x^<`Q?q3bhvv#bP&rpsJFm(}>rq<~hpLR8-1Sfkv^ZP5>e(hVP|%S_Zs|(XF5{w|F0- zd7IJnB)6dZSCmB(Jl?;`K8WzcE%nt^eyh4=R<;O8KE6W6y+LFxMfOk6D#JU4?o-ezPdn9ddQhwf*~*<$CCj>+w{ija0N`ghyBa>4LEUa3a~^W@KCki^t0=w@U4w%yl(1xS?CH}$ znQ4kl?t}I8r5uJD_DzJC?K`L!4N7J0^l0aG8I7iOxp+`C#n$W>=vW#1XkdN2??EGD z1{J?UKWr#(ti4GxS=e;@`N(TaTQ3s$UytwGRFyctX>(#wN%K8D#UrLR>PWQt9cD5D ze!W@Vt)33nk$QpHVd0KB+KqX@Yda^iWepbND@{S2`r3rc#?YK(UFGTrxnBYb_GTk0 z=vw?S^i+*pC&{DMqvR+p_nM?R;kvyoO?icEd3WMqzBnNjf$$Pz=2MaSHt&KkKT6b# z?BzjTr{1<4&?T?cZvuNfo(2xGO7Sqz3Nf>~a;Jg?Ab5XDA}mI-@X&_B;|-6=0Whin zQsc}C#Z-?%o)qluCY`KBCmz6^|Q2w zCVwF`rs8vz0O?-WW^KNk%kjp5mLX!C6Bi+v^k}2iQ&o2Wo`@PVwEN~RECvpPk6$EM zp=x#AU0#Tzp~7meSAFI%Na2Ee?OyV^$;6mbRpmh!Otr8!&+cH=5migIi>R_+UqT{m zM_5^O%6hvBkslN7tTRg`ajx`swYtB-+D*-*ru}Mek76q40n=hP=4p#xFtQPF0ApUp1TilRT8sHuQ*E616{45%oh8VU{?vWzce>XPfFD_AnO= zr+7yv9c5FG7SeTb*icEXEjK$YB!K{&CqPF(b$6>Z8E_5xMrZ8WtzqXIK|hU?oQ7E* z8nHA+WXlY<&9?3VX$;CQ%0dQs9y)q?C2+3soA0t!4O!J*xdjD-2=m*eBvI89X)e^u0J;?{|1-Nqi zjs?r&N16|BR3zAKVAS~?*L&BTJm^p|#6Sz6(m|R~IS|e&w!THn2qO=NU?W3U#fJgb z4oUomfAyvhu#0;~z_`%tS7k3-|1)exKROgu`{zdCFs zHS(9x@u8C7)}j82{Xobs0jFOmxZ(SYx=W+d#xK6^D`*v2$z?EQ!)`Vwap&=2V0=0L zPrCeO?ccx11TWj@XNeaiS5ZKSM|O+H$c>mS!V_0MkIcAk(J{(ZyY0jbQU2qK<~Men;e^U{KD| zLvis|XXoIHkE`ngH61#Lr?MYkYAUc5@09m}DBjAw_~doFjo59fxW!;V@tGg|O>1t8 zU8st@c>n&qo78D$jQIb)Np6Vw0dSw(SsgJ4YOk1GYi5uaFsZ^jxAB-t&7vu*W*`N0 zu>h%{m>>Ibr26fP~NajUvKq zr0>^I9;m8>qF!naLnoOvk%M?0kdhp1fY6C>8h9`Mo*MG$lib1B>Ctwpu&|(9fF5e~p(}r^_V; zD^830ja5osV6=ppJBwX?z})c0{gj8h`&$Tw_BstExaX;o_y4CkJF&a}dz_v3^8W?S z&OUWh!XN`kZL={5b5x2MuGy!KYEBfiNESzUc*K_Uw8P!YC#Nr4I;-{KP3LZwZ+sRH zGP6>PB_Lx+nQ%L)f}+n_gCC_|KHAAOXdCcy9a@3F)YG#r@Vb+7sQ%!0Vob3u;8>ZL zz4yI*rrUu`{`4jRDRYKSjmxV4hCc(dMI8Y-WB#gDwZgS+@`@56F|Z214Zo$VTyl56 zWHwqA0#nUffQ2-Ea|g`avGfIt3b0Y_C#BKD|DopW0g`TpMJ8g9(A9NHA&c0Bp7>Rr zMg6CH#jVMTp^q=ECjnir$>xuG)ruB= z70s-Z2GrA)i_K!KIqp91%`TK(k#eOxA9z7DuZn#j3g8=sAhT9Nxrz__M9Z2`)RDVxA(Z4iuj(Nazx!Hk@;@Y84XL8 z?*Pt+&`CY8)$0XRyC`CH(1E3uDY~$?Pyd59PZ`<7Zc$2&>Fjj~Oih8X`Fa@?Q*&K=%{?qcNlH2oOBW*B z%~y>3!fM>_lnHzaCk9H(%6cS) zdI{>hKYyNKYFrArtVZvj2hX;K!pw%u0{KZ}W>!y6PiK6xc^^{4dtV!p-urRt(p|M<|fOxBX z!r+y=;|m%-P<~{Q;(IlqKUWwP#tG~F)Od5YXwJFDkMR$k*lw-Ki(VJ0?6cdAd;gx zza5XFnA#wxafe>Y-rV$A7Lo+1w{l-vGvF#OJK|N7YxGLR@qWRW9a=8`!goO6sR zy+ufMhp)fH0dUK$v2?St28;?*K#vSQ4}- zZ9vY8FmIKEPE z-G?V<)+6I)V}L8O`)_D8s0%XW@h!OYua6NgWR;6PJ_SW2YhNuTmqmsS_koHUnz}#- zp(qQt%wp9>F+G{`AbfoR=L0rvh{TwX5|s4ki~GXn!!iY$sP|ATLKS~}XKZ#D9?$Ox zZ-S!EE(NSJY2?Q`PmZ--+urJR*F_!&1a}TzO6GA=?Ca}G z;=6$L{(@Uv9g_CF)(*Ve;<6Ony~qMh4rnjfF_0i5Rde)RVXXz@d*FM&GaHf}S7r`Z z3xzq47yB@#iwzq8(E|KKqp8$izBafRtr^KJKk=Y-XD}knynRm68HeCjhS@F4P};^= zj+ePM+ti%ecr-URgHcjed)uZLiWe}FeQ7xb4BNXcNR;&N@{z0r1)kwNmF*xPHR z-@m7MrX9xFcDpb5@-80gUG4NH@V<3bT)FA0_miJuZ|N2fle5v7I>*?=GC^3ukHqMLR^@7DXlsG#UHx)v?GWAY+u-Vk*wTfxjMrd%BQ@LzSdXQ7;6aMpS2L(7mZNE`m!x^6?HtPq~)ndWlNYaXos{2gBghO&q3$)hz+wvG+ulg=G- zd`H6ST=LF`;jJ@dEkUhQm_GfmRdXD616o*pn${J|+X%1O=VQ{X^^PKNT>zH&QpZWR z4h+)Vm_G5%Z(y}$qZD$D1+-=MemAPIK<`O;jX@i<;gL1d-|ORh?^*yYxV3KCUuwxh zt=Q_Lo%}`Oaa^;=Ihg+t^PIUUIF4g{58cQwhxl?grh zuM>d@kfvs!%=td*ZvxgQ_hw%^12tF{@&d{H<(I)oQS7)Ww3y< zs%Uk@Qu-2HE%mdJ2HRunxp0+Y8@fF8XRFR5K14!ID?yNWJnrGyVWt$GrUZTTvCzf$A-Iqce{^4sGls41^rw2t2O6iQ^@>@Q zJk4zQ`1x<2m!xGtgM>Uk8(-^SYsI!*k+TbHiW9a_9I4QIl6W3 z>!Z1ZXBwaG3da8W=$D=3K74B$$Ph+lxwWlsPz`oD@2%<4G>@vs8t3RZ;t@#e9V67? zjI_l@%>iqM3h6(a>Vd;^<()V%1Fi{wb$aWKak4F3Q=V^cBo_(d%E5Y)3lib7UNZvy z_Qvjy`TC>$+>cduFX?^#Jzg~k=Ix!`ptk873u5D&oN(UhV*YUad5nC&ajwl_;gK=M zk6im_r4i)sy?gWNHs!4$*M&2e4I~q5-Sc(*Pry#M>|Ur%!!&gLf>@MH6^dr79Uc_RN2tL)!N=ZI7KeFb)Ak845ixr?4P| z0w0bW%?e=wNH^tH{TIy|qY!P!@jEJMVgby4w46Nr8f7M?fYL77=@!K9oAkBA>$cwK zY32T;ax##o6gY&$ycU3BlvgVpKWJ8(Awnp48#2$69FF6x!(x}T{<*K4;WQFC3mme) zxDeADVMSnANGoVQ$Z@drs7WtKPy@}osQqaioo9U(m3mS!6*TOPcpdc{3+!BuH)S<-y1f_FNki)3+k2Nm{^E#A*&UQ(<8%27JYhe1x zpPikiSunA*6g11hfQhuF<0xQUEq2=sna@Y}A!D z`C}`_J0*2Q{77Huxp=^<0};8E7s4ljX&AO!PfHXP_tDnqD*HSju+RUa#Wr$9eEFA6 z{CzqpG#IM*VEHwxM%kaCd0>*a0G`$^SHYEe*5HeN3W4M!r(hb@!NieGQkHD|LWffc zVBrH<^;4Cy<&a?R6`6^;*zTXgleagY_KS!jJfDs)1Fta>%#j?*)SE6F$y4o-1JhOW zbn9weaC;-Vj()CN&Ez;RZMg)@P#D684e)+$x)~!^?Yw8UcyDiGa&l$3V0D6C+hh%0 zJPcIFC%|4i?s78*tkeWJr`*XA-pTIAZGg6Y8FN`VSCKBB!#MQ9o3##lHDv;sio?a| zBz4fmNtDtYIJzy#lHYWL{PSXVuQ50(9MiVJxU3Etas7q;{L=0cA}YR$b4jKJ3UW3b z3qau@t`PD3CgPp@(K-9`eiJ(v6f@UOU zLxDBo+Ws(F&N23_pSW#=Afm~AJtDGWTVdVk^YP+2Y3VMLp7KTqa zfJx1KC%~K5F?0k5$(jR$bd1YnOs0IYQ1|uDd~UPBKT*x)EVa^<7e0F}!AlP5AwoNy z9JjF0d+=-VS4``G-P>Oq=)bHx67y?Xp9R@#2)8%Tp3ir63b;rb$ILs#%)`) zN4|t>f35>93nl;v<)F;cjHw)X7Ue1z@eUC`OW0sk&-=f_Vu zzEz-cOF9zT6V-hyEQS(c{=(dC{PZNXsQ1M%Tzj>>o^!xxRwVftL;=)}jR(*_^o~wU zdIS@X?v(}{Bh~Ix-MH8aLX8hWrz;=a@ozDGv9#jmh#WZc?3p`wL|QbhTRv|3u}GRQ zF*li#+BY{}Rs}DY-RO4dm!vl|y*rvnzvlKsdwedVPTr_cxpg4nP|Pn?_wp$x+=ojC zazX z1%mhf-sxgDY&;wLj1>GxcuGqKmV_Unhf58YlN8QP@XBpg{)<`kT#P zcMk2j+dTq$6eNIYcLY>#Mm+UFk&>8U{xaA92KCq9zqqZ|yJa6)^X1e%8AV*__$~k% zE0n^ib9><0C?h`7+--1K{H?LC?bpzK1vdh+a%*_;-8~|`!YCnP`mu8@$8r1a3G{ED@9#2_+>e*LdBu2yz|2B;9ia<#N37OY z@Cy@erc-h7iqmw?eXtm(U-4JGbiy&}Rr-rcX6cF0_1h1p+MAn*_U2aUQSMw8lM9l= zy3fR7E%bf{R^8tBYHRtv))M`sZG|A!Um}&|X+L-`(MX!-i9#=^rDIs_X#-9kQodfe z+7rJdpocX^7r%*4*d@&k&F0+;NSk1D1J>vDQ<>e5Vb#e?TEUa9t&MKoO~i$o1nv-6 z1|KzHIO}~Fu~(deQPt@hAJv`SMgO=B$M~&KBQ(8SEZq~l@y`1VvRdGFyNT=GR#Qa7yyJj~tuiWF-24YEW!DyR% zsf{{XgrQfV^nZvyJf3bBaWXNk?g_SeSYlpYyvaLp7a8=`7rG(RfDYP-Q2)&*x+z`g zk1r;l#V>Q20F?#5+-5D|uu^qZfU3U?n3+q9HaYLim_2=B<9+#2{5JI@9jtk;ujix6 z+3i9W{+TK$#v&?-SQ*+yH33|sVMI-Ge=x;RZ9*=ofVgerA?Yr7U5>9-4_pwH| z2$ip3n4wtnp%59x2?fUNF!XbI_Nz(58nmt<8l=8?d0czd=t#6mj|` zK9ZwKa=gv5UqBq~Xu8$+LE0v%2*Qx4+rf9 z82Itu*w`X;f?akGqP=ya2$q9eMKgjFJ)Vj7hG!3?aY&aX1xIR37{6fUc{nRk${Qj- z61aFcP|V&T$@ehVIDv5S>XPrHLmpP5ha7DQ^s&xSw-d}z7IdC@HspQvbmO;$o}-__aZk< zHIVzn97)oS*9*N`dl*jQJ^Ns>{O#mJB<_YJBCIV`ZTfrB%-Ht_O%j%g^xTq0Y`#i- zv!((Kp~MR7F-3$5wxQAnlZ}qCDc^5!8EgknT``<-{36gEt~dB2EGeHyU8+psZfs}${DUTAV4@Kn zltUUy70P8kYjXGWo>LF2eMAm3$5t5>(+#@*Xh(WVyp{VjC9g8^iRyttAZZ#)#X>*H zgRV+(TGYqZjK2QDqO7=`fx;vE%-n`5&gjec;$Ar4H`tu2?+(bIdDic>^UzA${PlfA zM|E}Ga!kNje|8C+`F13|dYnzV6`{0F7_puN0+&6|n(@v(ksfk?lxckH4K?ppK>t&= zV>*vJGT&O@9-Z_>a#x>Cu{_qx=r4LmD8jST-2=@1v<_=KP6nuO5ASq__v@$c7%Sz&%5Gzu zkl3%tTbP)G(Lc`|o&}28zg@T-!6x=Xz~I(B(=N+>L5ZsFrw(*A$s4W1;+EedUO8;N za*>apBBs<~Xjma~&hLcFlLMEGPLp2LY!~!;e)tI$Js_i5nU6 z?%)!%Gdg_SDznfCubWAqGy@&omUp4c$eM&;;!1^Yb{O{(p%)gqQf}9Dv#n+mgaRqE z*a&UAwuB-qJ(4?hmP50*{shQB_;$J!V={pDsTJC%xIZqxt131eXYj1Q+fiV7jH9ik zs2Yj5C-PjG@K&edwAkUDhq2AH1&amc6E^1emon5ynx>i-sN0@!l83kFe|mMz*UOJ6 z@Bw$fgPMG^wUVUOGi?H6YP~@Hp4&9@E%iG;(*D4|YLWQl8rr$@e7R|I9Ui0WKI#^x z9A$7wbs03|iLppNkER^C&f~1>y5$!n_2Y7*^_QjlB4r_$;*GPmsG6=)%H5&lV%~L9 zpY;~Zv8@eL`YCg|cr|S*A?%IBiudsj)K4Vf0k1{d-jC}Ym|tq2vCyi2Ho!PRK%{~@ z=FY*@ms|Bn3SV=hox2wATK;NnCB7-N5rwetOd25LW#d;?JSgt9j1`#Xv3S_nLh0@n zNv}XvMED#^VJ+^mpmiGZZkD@W;_AU|qHy`1j!-n;bLW#R+Yx(|FU)sU&=D?Xx#=w5W9=qO&BHS+|v4}0XzSiP+?ip0?xa8Hy<3h`R+(sjs zDRJw~M5WCN3Ei{0W4dAS2)~x2B68#>eWsSkwJEI(XZ=>RA;a<^o;icjaan zB$cBm_>N-i(dSl$>n{^j6o(tcmSe9i-pJ;z_||O2E+-Z#5)dLJvHTfFNM#zkm)f}$ zZq)F$rBkrfB17sJ+Qp)O{YT`3>&#p|Qyv?euh26*$9KpYZbB5d4h4LkT)7qR-SiVY zdyBcbXXa?4`X46o&K(bzM&n3bitGjUS}-jsvOm2Vy|hhl+?MG4c^}`F=bvQj>hQA3 zlrn z^w&)s{F|vW9IuscwQi-|p`|D$NeeG&X*gC%khN(1Ew7H(H*6TZ1l<7J(N6AaSmsiJ~LkT!l`XXjk1c%>)rmQid&6mD2iteS*TN#g`c3(@hk7AUTNGYKL zw93L-w`r%eZ2M~~$T@|(Zx^VHOKa|G{W!}X{2N>JVF-@NCQKNsa$@xqM|GFKEOlZn z=U3SDNa1+h$IbE;(sz;2r?4&-+Y912)fu&^-VoGF-2muZJs)#=q$rOWt`9xF*U-Th z``oouWXl+}+Dhht^TvM;dk;QRu&5axGGUFBlzl=vfgMj?iISvi;~u=9lnkR}R;(;- z_x&VGAgJm3TNawJl-<(DqM;eK58dC#VeY!4swd$-A*T3_iYer$!vudAXVsSt`hx3! zh1UOzuBjRDuW*?6IcLK7zrtbOt^d7hA!pGRdhoXjo|iCDmo*&#kE*8i06N%l4~;{8 z+la^t!3t61Ftmy;zzqQ?#IgbTN z<9;$Xz-V6HLaTndFU|pK8Uao|8*p=!i!NV8m!`+7iuKKj1F@br?Gq1X*Ri!%AJFG^ z0MxW9g1^ znwx=mKLZwR`i$&~N3-B|TLUDSSs+owe_bWp1P$CbaPZ|&d4+&=6=4XZg&EwbMvcNGMCJ0anDa43mN*r&t2lNH(#Z9=N?`32ng#Mh;NM* zL;#tH)4up=tS>mmqw+Rdhtzj}0Tr^h_2$|q`O{Rs61g})R+Iup=MSqf-sse5WE0_{WfYrCBc$9Oe?RZG1y~I`aTlJtZG`e@Td8YoJ&K*H4nN@(Ud5}@JKdo!d1TIYZ$mzsS6AmHe=wTnigj$$3#>K4F7dhAgO z5bplh3-DPi+|J2Sk!rzb@9|ngONVb2g9( zp5cag8RRS=Dw?2I_-h#ORT zI*_FS*_qbuXc^2PoT=PU`ZTXdpoli$ECFbR0Sy9NF9zv=?A_>-4Q1-snRunxd>aTXoXfSPJgnv3d&%U|r zMUYy>qv=w-U<3yea3m)_08W+F6c7gc<=(JRZ;zaracD#BVhwvOhjBDscRUyWVx$;b zpyITk(F$N9jcOsAHgSmbpX?Tk|J6SEqNWsr8`jWx@q%?{sriL^r!O{ppygR_&8cJl z27WfGz~E-L0z{#a68w?b1{V~7hq>AjiKBq-H}yq<_zlt6vbg)sM*sTuUh(&`s$e3q zpV5GJm5*8ivS~HIM%1^3d1ty!=}zT7$36+Dx)!EKBqrJ{8!d~49iw0~_Ar1po3r>hyg0w;rgra~VqyM%auT26*6?VFuHdvVwT(p4 zImM5Z2s=f>uTcy@O@#r+xkc+pKC|D0Bb5LMJGsS*)X`!x@L1a%0}-^*jMj58Pzd9Ynnj07_j>+$G`=tdS0Jtrj0hIEo;%oVuwhP_ko zmRWMhARrE=i=`3kMN4!Ay^kuCGejOKP<1js`x*d5xrX5yz#|zxP`!)M2k5(-w7cjL ztzYQv$<7a-IL*}2)eNOTsvpK}zdaHS{Pak-Ms%S;Qc!`|^cCQ$`c-P&XHAD?n)CKb z3BXk68tyw%=ff*{pGyj)R67v|v%CL*wYEI6GGiF~Txpgq<(Kj57~CYAPKq!xBzK%Z zBwS2m$mHTDON@vDKhCs5dUveJqB-M<2?KM4NDmadtHJ{*AtGO6Ru)_(p#JLh7E4_p z;Y@eXbLfh~oKJn|sXdTc$c=7CAEsJnZ6fieqrRw0Ix_ruVE16XHyE|~)bT-s0$<|> zGYCc+C0+388pjXLiunZ%&Lvpm$&*!An z^?U|mfrX@t|Mb^-0$Wv*IR;nir8;GRZN{5jmff!cMvZ&KLYLUuN z3j+ValI0u$nke2>>RuR5z<^^kCyn5|Z;Y8nfU?9b!5)Z#2wyN~c7fe8L6?|PjYS?a zRBMaPO0YjLK9ohismF_Hj3UH&^w|2j0dZ_VKMlVaDb`Fk2KHx!eFjn608de<)Pq>M zSr^DR>+d2Ovlt4rP9fDCsL$>pL!|H|QlUJ4rY%LEFVea5jun@fvQ@3@sV!XiG_OX5 ztrliOA@o7hY8SZ2)R27Z3mI^q_8pFR$)G|Ydjpxt&1fwhJ2~sa3gNc7xrE%l6C#{$ z_=KNw_th9I_$ssjvB3WD;jdoDQb<(2JA0U~)}y8>9r+uGc;}~C8`CXZ4e}CjOT!|3`ym0D4W9L(BmlJz9X)D!Js!++hNmXOw8S`9-= z7c!0y+N<`(Va6;Nx0(8#HZX#&EQ^Kr9UWY5TZdXQHmCAiHX0rLv zh!aiqmsdvf=%GXc_Jz|d=oo46pLPg>w2iRxmJ2@WJg8SY;~@{d7F3pZY;%sPxqX>! zB5wBQ(?vp<;J{D4JhgSPWzrsY%8sW>)1l)8X+<%rvHsb*>wL(W$d z*y~^I7H0)c?}pjwPw*4ns)o-}84w5C8{tgORv1b+-nBl&!5Cw8;!(uv$;FAF!fQWX zF+N0L&x})%Q0%K4?GnD5b#jk866)KDs$cVke{lcc`I}aXj#U5iJmvPYyE8J}C)~a4 z+%H+fII&|Ba;%oqoMz$OLY}^DN@S~m8MrYvMN%wMCCW5+Ev&1{YbHyEon=Ly$FbA% zzVbw+%6qvP&M@4gN#2RxwACfL)0NHxvL*8lR9@}qzE<1WV?&sh65vX=ra_b&vlooMm@UQ7g# zoI9}F@tP@kAfH&HWW?_-1@us{yQDhi^S{mLvp-Y6pRPl;z{(+&L82iqE0mq;5&L{p7*^k0r`eg1{=Njz|qU*ICFaX?U>c9%YzoF8R6&r94h2*F-sV zCQ$hPzHd1m5vQf}TCD*W6?&}pJ8I+U^nHW!OTfQvxCq6?Mw&XdST%;!TKG>n_{TE{ z@85H6Tkb3MXM38%(<)*5RNxD-EQIA-s^f|E)xpmwACYqKIL3QWaJ|Oj%8bL8VfOBU zlesR2EVnk?&2x}D&Yt{2Lh+j8WB17QV{sbsYMQ1(0UQj1*c^CG0c7Do0E6a|w#b7Z zXRuY%h(Vi8yZc6cc&7`SXbrq|tw+mvKTwtCdL(tkzVj%;J5*&Nh>#NMS@j8fJ;;@( zEh*GJh){=v+=fH?`*5V4t)5^oH>u13i6KGWV4;s=S?ZAro3{#{wj-*r+gd;0*ol7; zhe=N-__P zU1`M~pJuIo>W6oAXOt{psD1Fxe5Zen4kX4=mn03Q%-$CW zWmVg6L6JpB>6yI%D%obypXuXNM4I`i9D^J|(o>i*j@f{#Ql0-e+uS2AemfFYysL1F zzinYX5w4ebY85KZl7EN%SvdV)!QgJ0IQG)>k9th9P1>j&WRpu+cKW&iVQf zjVLL*$ou2y0^!N1E*eBA6)0dGSXJckLpt_o#SC;kIRx|T$Zx5S1?J~k>&zX19IFBSF zRXRSG5pzHiG`1Y1IzQps$_&3=b)AQl=y=5S5Atpco$-+}iRr!bPfa8)bIR+K{msNp z66spv`YCMjLMp9qhnAUb&_ya$)I2G+JyQ2s>vOz_P#1FTxBKhxe9A}rRqkx`gPd{B zeT>~^`1fg*IPj(3a|}MJylpcFU;TXaq#@H=_g4jF$`d78@sRs=P}j|z;O@w$8u&d=s7HU~mk}YdSj$6FHG4Q8<=6sA zziob3rBxk{^A1JRJoi_UxkdW+*Co{XMk3PFzm=xIMPC;{OMFE@bZ=T-y7OGHHMBI? z@2=yXOZi57uVR z3}t}47tl_1`ZV`K6uW8g54F30fikqj^Mr80^os+;zVvXlS3$!BMF*HuYT*hpKI**&N2`RYwvYaAKS= zUrE`;Z6C_cJQgN=9$DR*(f6ndha|u97nO!(ANx=ToRwhn+));i`c^;UCwXV;M_B<} zCWwqoLYN|1tlo8xlWdK5XqF5oUOWF30tj1bBS zANLV0N?AxKoUoqc6GS()hMR}PNpAn~QWjPEop8EzI=PdLVNzMBLC4;);=RO7mNW4w z8K%dBhwsd?S@iESNk-j+9)du+j&jNn7(&f*` zacAy+Nexl#iq7--9}nmMqf+eug3$Y-SnMB%DugG1U*E2?=f?K?v;%y%MV0r#jFit4 z7*n>dLqu{pa`)nxH{VhU8XcVQD?t|G0yq@y%3F@BfC~@B z_&SUTtjep=nkAUxd$_&=PILHeYR3~28c7?|S^R+0(=yd>t@{V87k^{qW?J}x9rq{K ziz{A6l3ZYst^@eX9^N0o%ZBDE)H<}D^$6R~>R6R+|5scc84jzrwMyrU-6pzF__f2L1DK{yIF&fyxS7}Gb3SO>TGXXE3sSi*h@CND8vYSeZ z08?)-HR!vHqL)Mti*57ROnlRbj+q898nldxLXQgbgh>Bu?(AJ3B>dCFgEi;xoR0P; z7HfZh_r}Pppcc5{$Slr*x6jbH!n`jICqe!+n$Pk)%#LIr{7Y- zIW{&IzULC#u5&lGTRSKgXXXc5Jo?Bqp>MTwYEj&)hG!3^%HG>d*;fo0)7!cACskcN z=ouj+mxXG@st;L0aY&D71WZ0i0uz?|(nqRBoZo=hRedkSs&80)Z%0#2&e{L^%#udT z^&4nj8bQ`r$JwP3Ou)wM>o?hCB|*@#acyiXVQXu z5aSr}U6FreU?5^ug7ZuJ+VWVU9yP=)m@oK|=4983sd=FJP{DF(r3W(!v zM;oJ^VdX$2l{|EzJwf|=f!jgc@)8Ih6+m1-zAn*O8t(Q+0wAopzdw+^fhzPP};Y10Pq0c zfY!7f^w1oGX-PvE9#R2l)TO|cTb3!%E>q(GOrh22S^=>xzI;Q=HCR(&X#4g3Oh2+f+w9_eD!%l^N9R-p!y4Dbxj$o8G{Rnm+Pts&iQd;%&w2MR zrII!S;^oYhLuBQfp3C15`>*V7JFpwt_q^#7eK7NQ%fY&I~*j<%aaTdpUy(wm%1>89POn)Ww_-KRf45gA&2Qi=ChlCKoKS2g3RF6&tmUR5sPT-9nVa#~BL8BRUas*9iihkw{<-J!pu(&;D3 zEJvoRX5p8t4WAGDow4ZD{Y(P7+{_(ZG4|`eEBDZaIa6QN7|@>B%zcP~S-?&dOV|ey zkWHBLXrRZW8A&X8Lva=>qm}=T*N@NRdN- ze=T#QRa5?pWdoL!7Lty$o;3wJH?1)kgF`Tn?EofL9=)lo&mR=2#&dlc2|*^=nPP0dnSQJ&R{M*tZ$oqv}0xGKHrx`eG%_>vrW4lun2QP#r1|FFc{Qe zf{nGXEIRk<5x}cf^ONXP75|o*I6%@Vql3|Oqr$JZI##d~o^>J8?mGi@D2=nL_0t!s zj2@yv(qyZ^_6mopZ)4Zhj?;V3ye^wDaWL`;(&jeq@xM7_m^mp-E|EuQx<6mAhrLR~ zbMIAHK&)wRXH| zH#xlH(4^VZ8uH$&O-E^#%SR(4NSJ-_B6j<@`X7QexFO)EQh|%+n#{+bo~yGYq>Fz*sh8Tyf&VoU7>T{S4^$MGta6 zejM4)Rg4Dk9BxWlWm>JB;UgD1T5?NTN2@bFA{s_lDD+g39@ZlR8SD|4Qn&ACsNoO@ z`%voC-*ET3kY~cjon-RMwG$aB8IEIyb%rjj@iU3Vj1^87zlp#Y?ssn}bB2DsuJ_N- zoNrqWf0)6U6RqUZ<0U`g4fT!>8n*Pk$d!P+BCpM6Y>tkPepV5wNSuc`16o6iK7T{? z25;}%3BV*ffGc4QGuD9yslsffpLwLV0M~bDmZ@R;M=R{_NySzRiT}T4-ncO z79C3eUU|b*PT74&TK0+{ny`ZR7{n(}>|$KVV-+B;jAv>7)$l*s)-}gudd4U*U~-+X z#J+yE$l@*fRJd>uK4t8Xa@@~Kj>3L4&|F_(!u!bQlWmw;LLLu_~UVx@q=7KNLa zewup_rcO9(lXn3RIwwV5mJ#Fp=gQPJ73x0=XQ8& zd*WNtoY1+?w&Ti6*uttB;!WG-O>N6l|8SK{o3J^_#il(Ym;ZVJNW|+bEx`lI5A~-L zIdd_-CQd4B)82O6b;{)~Q#Zwz=hbgYw^R0txEjl5Y6ja_B}~7ucj2Nx$zj%<-)O#9 zRjQ_C&L6onWme~X{QH|-(a*_;$#vr3k;r~o+jTyFkQSBN0^i-477{GhEmOAkIb5DU z?ib?FX~UR74t=G4XZQX!Of4WQaaH1|KN*HSBHiD(SKVYd9iZ>7b^}vE<;`E{#;E$h z5ut7spgSI!fY9|AZP^=S+1a?#Ls0k;SGXKon>yS)?!7*Jc-^>aKKy=ZQ_P_Z^|?-3QN25YU`c%!>j=(`4QDUiz#(+oJIroE&2(&-!2pRB08 z{Xhe6?3CVngK6E98DfTuN8Hw@+2DMW{kZ!e*t%FGPQ-b~WUF22g)n}w*$V{pE@{KT za3K{@e*V%otZvul8aZ0Eyhr|_W)QrE6%hn(x>l=#D1XCmGO7lXDTZ8riI4az(x z`sgK=G!ZY68Uv1Kep#WEx7Z?Skm23tLsfJYr>xL@2yZO8CQq<>IV2ExDl*xEc5_=# z`RuwnYh8FJFrrx&Is*g1!zXj&V6@si;in@0A!COU73&;u6#m3r$CF2T(vebNa!6{E zh(c7tE(LI((_v1NeVtJyi?yE_0Z!%c&xKOKC#=?mNlx}#{cm@52kI4qPf9Fi2PWji zFk`x%DyWZF{FSHg9`x_9OeZ;&AFf=a37{z374?KSuORn|ZcOy^q6E&mxbg!&z3oSPUH7bA7-#;>h@UY$}!1DnGrk%eR%U z@t8!GoOlbcd6d698f?9ue0Npbl{QhD^{3W#uDZyr$hcG0?|_9yY}Zn}-tLvSd)w61 z6RI!iePezjej9c^?>fq1M^QA+s0>*s9XSXY-|7wfE8q|1Y1!|<=j)I&C*X*fFq--s zdq+Njonvu=MB5}v8(%87A4<4lO{T&tOM+1QDNQ3#Gdp}6zYJqA zYA-fxb9y!QPBU2d*KZhBM3zWL%(V!mbbJa{?$3%TJKytBOoR-^*{5(<5(T8JFD-Lc zJ#^)fdjFm}X1FpkL5Kf^CYEJ#@7}Lnosn=7#>~&|$uo?LiVOMlN}&ZR=VFR=nXD{x zuhB}pBu+%ifo8AUWT6?MOvb*V6EP@eg2dXasWE20hH8a?sT1#?=l2p%I$+Zf z81W3pZ%WhMRUK&k*t!6biC_;tdw)+^dd4n zswl-7wnDV)0-x_B#&C$|HhLYx#JrD6SZq(^YpZD~Dus?i?MVOH5FrN6-EA^guaJ|l zg-Zfqd&Jw-my~stPYL0}_7nql>HBjvUJ<K={WntH*aTr$OAIXuouK9 zhT%RQG``x>-wkq0=)@f>N_E;6=0%Av9+cH+%m%Ezz=1%D(Nx)~)$ z9gdgB`JDE3#y^g)mS-~LfwEYR?r2VW8~!jo%r7b;)=>8T<>}CmfiCg$_b+DEt~oOK zjh;+C9=q0wiL^5t*y+a7AnFf4{qZ{gb|HpEu6@}1Gb`PlLXDbixaHX623h2Hj!4cG zL1j#mf?PxFasP2^4yiZ_p7NMW%z>;D)H)_RKlB#1Ob82emHtgC-zMHdGc1rpx2c;w zznQ!*e}pAC#BDM^m>dgBv+#_;NglZeswzJ>e43Soz1bDb?%BhIMO667`op`({`3jR!$EWu6!vZ{X_zn@|}6g0q(Q3_K??-56&spx~g zXu{NN2lb}3$x;nA7mU1hsY_(f$VIPR&fk@V0n}*SjkKiy>_|X8=bD#-n{$WldgEkf z#SrgQ$wffB_-?Y@OOLdkutGhkjhDmhi2HWLmz@vb$&-8NgCLH{a+n-QsG)l7ZZOQ{ zL3lMwC&R4$FGoQ{W9JtQ<~nb^{uivVS!X<(WXB|Ueu$Qq=9;I#C73Ebju~uln)NMC zvk>vMg$KGQx&}Xag`Xd=G{Lm5IBmW{6aBJS&ykKJn@Ll-_~B-jNQUqHV@)$j2-0!C zrSrkDPvzp}atL|Uu__HsRK+oY>BsxadhmM8gH4$fvM`I#S8X)az0)#PR`|l^rsC6q zE`%a8`5x7eDA(CFWq&74R|juU!8qjNev&P)6r^VANJ1nWwUn;RhPd36!cFq3x-b;d zwpoT^8hhnS3<(NPD@O_Kl12n>|6m<>Sl%4h-5xdVzZ_^sTBK}+IXzzRYC+`EH`IBw zjC7<#l7OrboG;Naa|p%=pZlX*Pgncw>y}*)t}ssYxJPCOfq)-ZtB=HYi|`}SsbLc~ zX3<8dseUF>n9KV%F3iwtZLYjDevw7+jo+$uCh@97dr z=()&yGURVq$BVTwQyNuUs*5NK2naH~+QB~V2qiB)8RFO76A!JAN`iJ}!8`0QtmxsJAa8u$*j^5J>?VcDy9kvf=9c84F`RNG|DOj!=z_%zJzPl(862gP@ z0S?WE$6byze>!=#r@hzft=lM<^#IJm4nrZpfl69xRw_eaGK=ofC}ru)1|}bm5v*U# z;Iy95cXg$v|NL^*&-U-o4HyQ<{>DcFCkIni;Pa@?n8S9W92{0*N>dJbVpY6qge~RU zK*IoC>CG=nBKJk!`X|2{@Qfr(=Q?vs8k~Mr)u8aD&#$6Gw{4pn$=Ha^#+U%h>@YR$|EvE@bvNM8? zU*g{kh|`Z3Pe}}k4kg>R`87oLc1Q~rXA`i$hL4bGEFVhr+-@?nu_bT1raB0z{`pD0 zT_{$hANq2KtR!2f0)LoobrtDU>~t#fRF!pD2=;d9eO~Xl`nvyfp0Z%ETq#bfj>z8E zjzsPc3R>cim9HvbNwvdL-sJj8aCcK`>o8?96CZZ93i0W%Oi@aU+$(jeX0;2M%Vky< zTK?B7wb`DGiq_>NYUaJK)l$x*=Z=#1NJhJI*W55!+`kN+Uoa`p#C*gh+Es$M2?VKL zRlXbBdxx4SU8qg8V!9LYSip3d@;<3I1b=$K9Oo!Ln(*7pGTxL2FR#X@E+5S5q_f)8B^_|`?cQ!x$YhFCoI8?(=M_?5 zie=RD7Q08#$ZUvjwf7iD+n6IEc*Lb`pL(am531rzgEt=fb>>8n^x2hDKw*b}X}VrI zQroV7M^5-Oee?LLOHoAZ(<{;m$IG5mWfkS?;vK;w<5eBJh1+h#mJ`ekaSxI^X9_Eb;W(_*{C z2)o)*=_}K0l~lWnz4>2TNe|7)Z!V|#Hs{+>PX^1{UQU(O4a6W|mOuK1wo&cGZI#hc z@AYH+V2Ci4g!%K`r`t^)f+w7GZQFa@p|I+wJ!-XT{^^!2`a({zzg|$sw1mwaJw?>+ z=(QDAAAIW*+$nk_jT}6?K_ce#W(YBeU}FU@km2B?i((g$yKdiSWPDIbHOFr~t_lch zziTU>W)g!JKK7xTUi-}%p{4Z@lFjNbJLmegHl$vEq=!v@g+)G=YW#E<{9N^cxvd@- zDREaX@ctTbmK9Yze<3`~W3v#n_^lF`#HNd^^dY${Bp8ehp<~SNbho)73Hu`&ncfS! zFol)^T=>%7GIzSzauCA4cMlUfTutc829hKh3p2;%be`s+@sD#cT($v8i>4qsXG57L3KSHI}hK#e4jMNX=pyPCNLe_09eNy)B8q6Ty32e?^=-A z=ohwy=WP57AIejIz8~dk%v?mltpzvbuKxLdqJBQoNM_0Z_e=f%iS+}bL^vbB=VeLG zuB>=^24XdEkT)?lv1kTU8FVtleY>=dQis~zy!C92#s>g9P(Y!t1V;h2vGyO95;HHW z)_9Iw1SOb})z%xApo{8yFM-p22V@TF04+rae9YmIw{t(x+PBJ@fcMa@{r_~1asA4}b;IWIK z;&*3mgoKgp3WaQesS*l&coks2jDYCL>&4Z3|9oU#1!FGvpF}VcvkY&@>j1f$w_xsE zz0?_M8NMMCd=~*CO19v{nF4J*cT}*c{{2r(xoN%1>B2*RE9RnKVG>Ag1x?zWYqG>k z3nS-1f`NCuE))!QyRW2BHRHA*tvcdMH`?iReR-$`dVS(2OZESO!GOyk+UGW4D%7HL zGJfTr2h0CBl0jUnR6goKE?)}H5|~Qc?#?#AKq6-lx(Oy@nbdU6U^DDMz2@#7*r^Di zX#+C=K&pt~Yy8=A46sN@bj}4#9^#@Hq~}2?r9&va_cuC_DcHS2UnG{G|>DUW`b@@2OyT+{zfo1aiAJ909TzK09PCXMHLBPi>0QW zpWM4h73vSsGhk3y_5P#*oD3tt1kV845w;Bw5(yU|gVo>sdIvCHebOIWghzp*d%tii z?jz+i5g7S@uKbX%UA#Nz%(8(S5L;C3v{5eR0+`NOph+^aP9u^hu5Ym)34&~z%?zwG zkyn2T6n~;153^F=W$I+kiAUk8ROLbv;ix&UkW-$nmUfB*Y`ywATYXfksRUoEfjt3cTnXzv|fJD+e z;B#>Ah&%)bP<8hTWPHQ|haE!J>3w#VLcBqeAd_T`7RRBBc7X*MUa{&)C+_ZgM=;Wl za~y354Os`9zvWL752t2&K`psGU0w%Lavcba%8^<|XVO7<)FB$jv^(A`1zOkY=&5Nu zD?0yfjsr^|Ks@-=f)ii01|3i;%i_`pQHT=Y+-Pk0&+SZ+R8H#<3cmb|)afDy2lt5R zIxWYC4>%hG{B1iSqk!?V4Y@B3WeuSWB6Qkd>No+zQ!x$CKDK0Y`D3WE6xw^?{9BP~ z=;5nEY$5!F62X9JD5bH zG@ZHLfD?9Z8^;S%BNAxrE%+%VfPj!QfVs{`PEJ;a~>AbR^6PC3+YN9wyl#*9_gG)uqV|qSueYJo{hP`#ZGRoKMc_$A(6A7to z`Nb-x;yU$}!AFr?e*bQ6mIz-uTP$Cs$hxoX4urdws_hxIm4g9!_BOKiyWiE(G+$I| zBc7~S?SF2Kru({|Ftx_~IuuRw!9!_GGOU^D9&~?oQuRARGK-y)Rf!Z9Sz7=o!ie2! zs2aqrsz?4k&*#Di_)UF($nj-)j*)&{iHc^AN$jMrPrrbExd=YJh@Wg*eV?9f+TtY` zN>-F5y469{NP}cZ%1jyAQb($+M?t2q+P9M-9*3KemGr2@m~cv)8G1MVT@;)R?`1## zI)3=u{q2v|K0mtdxJObHC7IlT{PXC8>g=21CN0jy9o;8Lx@Qp{sV?`INi*!{>d}{H z9THhR4v!&Q*6zQ4#VvhFH@dZo4b>crMBIn|+y_DTP3GeK4zi-5sH)FFm*7xa$}=Dw zp{dMyt)T6Q(2v%^60?QssM3>$d5pBCsDy^CC3)fmvR1v;JQ;_p}$B4qj%n)<`*G&v)@5fy+_9 z!9*%2{8qMt?5g?i*vsmC!LJxL(xS&8P?~P>`lkZO#0XmdYS&u!{7j@=lbSBh1J!FY zy+`W9T#Vx-toH8%sO{N$j)$jSPc)+zxxG_r9L{uxEFRxe9owy-82?XLGK7Mb!^(~9sp;uZ z@#)Xu`y6qDm0=}hwJ|Ce|A7fIOF!Go-{Plwjow5>2wU2F>TL;A;2g1+EDm+9dbI~g zbg`?4{)AkzoH#LROcNtL5;9KRX0J(#!1Ma2c3`xC1?aGw_ig4*qMp@(YTboA{+vhCBZXtgoQ30MOB#~-0dX2mm?HsIjz$5_a(ioK?{UR#N>cN@ zegmJKvd(`G0QN>^hW&kgonI@~e{izO`-ZD*DgOe4OubN4eij*)1x5~t%}NY}`Tf2} z`tn{yb z>j+(VcCf28fq6$1CRZe#2<|=h)Ug%1O z?F83@jBsg_Jw03SBAecT&DF)ph_gLJD*kTsh$WZc9w2`n*mtrYBguk7wK=`(4)I;mGe3_U3vPEN0tfGoR!8)m6 zKI>sU^;9Oagwk#HtCV}&CP;p+F5te3y5I@J#%A!Xco6ZQ+uqrS5b!^&e&qy$)T@QC z`;JcCeDb>bfdqF}XaD)QNml}4s?IdXR10lSeorQ^`u9*ZE7<&(!wEc`LjQvgh1>>j zasPQblKg)FG5Wu-Zc5N{`%RcGY*&STBfYkrYn;6LchQmevhr>BtQs(YJPvq~lwjNM zV18g=4qi=Rrk!_ZKxFqq|3AN}QNMqi{nG2wo71Sd9+2?*(XUO{lwJV#%lGWL5rCAD z7yYw8`%(nlfQ9jKZ|gZqE&X}~PapO!xO9TGjwCim^I-XPt*^C>QFWD@_3H((I$PUJ z{UHQ?fO31Sp@lvlSy%f`IFN3gZI$5#FW|*d=@tS^cud#VE!A%n#BaX&&0;ZX z4J1BHE~k1$()g889U`Oxyrl7|)&HykNn>uz_M{f8i+81?Zy4hV+~GbBG6=l>p0FU! zZ&3a3QPxm?#aktYMJ*LDZzc>LwK&s_a2>W#(zFw4f!4C zJ6}%4AIEXh02qy+&irzh+GDcN@Ob>|S42{-b%6==cP2@k#%|yGkZ0v? z?6AywD>1ap$MEKfeIoiN=9ZS@k)RzCuizwqi{goL2Bwx&c+yt2NqSRf}4pfz6r2eChS^Om|&^ErZf zJ|1r!nT6UpGd6gKKWz&W^uNlx*g=GK?wlW9z}wgZ?CRQ%v8c6gZ=SyqbsT|L8(iiz zvb~6YCWJZoN52vxC#MUbnb9+#ZQ{m|$lI&>Ix#6fpY^GoXdw3@KbrFZg7!!>aiITG z)sNus;oAtr0Iufd+7a@j{znx}rBOr`S2`*-;nC zH%cZ!!T7=pJo%6Ez(|EZSJWPiO?B=OCH)P&nOls!xW$J4Z0q@OmDfU%7qS*4^hT4z zd((X=>l;4aQZtl@e#42Q#R%nZb`abylYyU6|QU+%NA_zTRoI>C1d zcK}Y**{98Flv%&Qxd83BP2$mA9>%Zz@iUrE+!oMDVGavY5m0CaAUNp7&`TO@52gv( z*tQ2@1=9M0MU%m5jpayIqGZJF9NE-534}0%XunJ;CcCSHS?%{;9dG$UIr)$oZA-UG zY^e-mL^YPE7ST5eu%+kBf$#fbUE~?-F(O%2B4{%`Dd#jn0b>z8vEA zI+l{6;?E;0hd+tnSqv12p;>g>Yc0?(1U^xGWBmI|DbND#w$=C|Z~s*fW^29IdQpb2 z)AB44`%U7^^}Tr#b!vmj@_0G9Pcsu|59hi>8HV(C?@T&jG$97_M;`hdGlssQCsD|_ ze`k`}F-TjYm=j!E7xh=%efRIE^yioPgJpozw)WF!SS9VHWw%uAfD^kG{585aMqS)46*jkC}+wMauE% z8AW2Wk@$GM(~2enRZ$@@?VUFj2bN9s2R4Aj;g&cdI3f|>&!sN&jiU#wo92SKu)faQ z?zbCycsXh}biXNmQK8rF_FaF@+r#$V1u?*2ynI@pdF8+Euixzd-OXX{XOF9mwF3`A z9Z`)dx_VocHt;>^J*)jEm{_AJLbWAU%4yebDC8v2g)H!?_*~=pteGipeHF$k1QL)N zIj7s+{9J85_~|6bG9=oxd4j(>85vgdJanAfM_9}14bje9?eAKZX-<b@rv z@4U#tQ&N`beXJ0D~3ydGVr*M3i}PMneUde1B1!P) z%hf>AZ&?E1k8I$22^)H;e*l*(60KkWlC-0sH~0O?hn!leguA;`3=DgEI!}ti+12|l zUf|!lUY*1EyWfYeB@|!Yh=Gk=CQ)BJdtPT_n=QC)^HHc-8^dOrwVjAgshY?`(t<0s zVf)j-jrW&yt9SdGA5rDvJ3*sJS-5;M(>{IO_2?|YK#WQVs8^UZ;{Q!Cl&3AcFAZSY4KW^tlHJe>0l{r$i# zTo!fSI~+RQkDY)2{CvC)Ak;%gO-AtYfV0sqWjU4MdvtVmz*72s2SI$AG;f!dO!e)( zZSj0=Gq6*mZ+tXgiXVNQsdMlk&UqpM8ThkU?7Tf)RAgcKNb4JOv0iO>`sABJ|0eDQ zNneNS7fn7pi2sARHxGyM|KEm7O$(p2S&FDnB_R|cG?t1&c4HaFk`QBG#!e{}LRrhc z?_*zQ?1k*>%wP;6>ljlQVl4N2`u=|ZKF{$y$ML)G`!8k2HPw*{O{=t>I7xo(Zp5#kR)HVtTfq~T7d7Tc@OFK7AD{*ape_0js z%I?I*q&mndY8@#&iwvyKtC0xJ31Zfh{Li9zd*+>vVj35d1j((Ov7}D;SX@S$K;!(F z1TP}CF#E#%Phh(*&p%{+`y~3uFOlnDJ&p;S6dRh!2aEOFVo$_YocP()nPW-!R0sdF zDr>pFNHC9fghraP=N)xV25}o6PGD^oR2_JxB`$|}364tpSPDK0ygXfh1xCQ06^fBj z?SD2DM*PwSGV0lsVhKx4jXgfN!p@^=3Xlx45uvKsN%RTKFYVsp>~{)PN1r`=c0wO) z=hFy}^UmcPqZH|qq5)ry!$}GCWCKD)F|q_(GQ-q%{3ZehE^AcL)t|QB^?xKKBydB+ z!`<$QATnsAa=rPiFRempb7f^tU!o|~LC!Vi+Q}rQgm215DEu9)g}KdEiXN5yZrm`b zrpQ>Q``W6&>7xbwPhQ!<;R&#h_D2sLvN8v&sHBs3c`u@(O`j_Fg04G6(LzZYo&NK( zJp~W$_D%4FIY5Q~y&_9=hfPkd-+&88-pM~&ko$S+hq!#@$-<` zzgmo~9{R)l3RGYqoyg$Ce=-gmAEYree({T)38c$|Yp3K)9%CmD`GGr-@pD?}XaVEr z|MVu{?TtIjLRetx;^uHyR+b2yjn(OGq5&37JGc@Jcu*q%lV__b{0F-W@|0js)0=md z=v&m9z&)}V3Lw{1GU~`L9GA@;+$xpEimHI zYn<|D7=bwj(v7FL>K6>| zy|$E_ilHZ%%^6(oF|LlU(OOpaCLdQ&Ih(iBEH&jf>-c82BeEtHY$MlXCvYt~b+q1l zz3aJgG{0tbvaBbDn+}Yh+19qY#KLnEzJGrbKLcXOO#~RO%Y~)OH@p`I($7&~ie%*_ zRh?X=$n2rk@u)Ig`L&^c)wEG4)0~4v^bqPq*(Zkuw~(@(obM)*n}8d1WW9OUM8v zcl-(HHps;ZqkwV4UMcNDgOX~7At>M}?7-%0D*9x)l_M@)ylLouN7_fbJPfsPoiw(@4Su^Mj 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

EMHkJk`anDm80uugTPEZEkBfmxn5@34hRBe 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 diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/related-device-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/related-device-attributes-ft.png index 484520a4fbf3aa81f1396da5064145aa012dfe4d..83aca746a3abc1ef1e88bf449609bda2c4342354 100644 GIT binary patch literal 37267 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 JR~|nT_cs8oc?SRh literal 93697 zcmd42=UPo=7jDqarB16GHF3Nw3LPL`tX$y{eP| z0Rn^`Lf*Ka^ZWzn%X>a0xtZTRbIn{c*IH{9(RwT1dcWMtQ?$jELY z@7y9id9+0Jg^cVunY!{Tqkx>9rJKHn;Ai~@x48xTmP*^Zy1Ev`9fChlayG=rU&9H# z(V}}6A>{C}_o-m-QqQI*_%mzh7|z2(Z9a{Yrv2Yj9~~W(Xh%oJ(bW|_+lv=^MiF_o zx0g@U*`MiJr}14oy-Dhk?EU7(Gp-DyffNf~2X%fd*p)_UW%S0BQ>f|wnvj z1-xD6&sKtA=EPNM;!UY;U-_JotN!!%FZ;^1GGXd}tfdKFT5fw3e;>VPtdaHBehbVu z`umG)=aJEvhSn{e|C-N6I!$IWQ2u@XKKG%~wZC6l74`lb$t?LRn!mr_@ZB)}`}w~1 z|Ahu;o|1nDBkO_eOJqwY2y1jYL~|G;Z+K%)tfhj_qjuy1Z8DhT`p@@2J^C*mSqU4S zTvh2wUd~dSQ}V3**G2b}Xq>6Ta;Kbdz)#>D`1}@EKlMW;i?AnWlFQ<+yJx+9m37r0 z0us)9)-Vb~KSdyH-Q88@28ciPotgNq`?(qaUCx7?cDcHLn%&KL=v z2X;I=GkZ(@QLa_K%1vX<|C13exbz=}>$0@X&sjYU6ns#6SE8unw$|5ee7ws2!aZUQ z>QWs-b#3n$$JK>7;}Ew|n&+up8FIGZWQ_ev`tnq4XLmp#+&^J;LDY7m{0)eVY^-RM zgWxdj%-BO-sewau)m9JXEZ1ro+R4f%)^2$;#ngRkc0K=iIJ%b30DS%rd8rmFVCD|_ zjnBHa86FUKdkGcAwkXFDg`)3LB5JEeQjW7j*1Ef`pN_N0!~1s0pXZc+#NGj1r#rie32vP{Knq{&=6bwCt4V`M6WQ^_~-cO!1^MF64QPzE%T zfPcXH*hqp=*3qW=L%=F*RljjL`5XE=*_%oTUr)$VZQ(-F1uD+?aN1VWI_v1ZWrrc} zuniyeMRWQ+o>1#NTXxl;^QK@n*Zp151?!D+-210myQ7sY*lEHV3tJzP5k%24Tg{>-8L#>s_S_ayFxhyHy&eoa-Y5 z$Y-q#3R90EOKm44 z1V32wAlmO_tIhhJGDoZEV$a07-as9wA?AmYFRxgku96e0vPA#Dn zT+$0_bWN?}TxYg^h7ZjiN+`32{}oVzq%UtIrUYR9GiP}eEssK`Mlb@(!DbvpMB z0AXk>T%K|_bRnDI7)`yPsj#qdHD`|qG0mS$qL@cM!lW@-Lixd>%f zP_-d%;v^|NDStxiYP|*PiDi9;6Z7$t# z04x1rabpq}Z^qWv)$;Kak=-^!bR(=Ov48MrN!2=IwVQY(DZwb+yZE3!X|SKG?5Ngw zF$BA&maq7yFW!xOB*R_mxhQ%4x)Li=`+&fDpQC4 zRUoFrh&9InYu?tM$DUU*uf*X{e>f-0TA=X^7N*J10#cVXyeGcX+DtY=2I#{u-I=HKBh>LA~DY zE2sOF6bZy7=GGbq#VVvAKf$(!$8dTt*_yU~Fedl&(kv zIYcwS8z@|UA19YBdE8;Ja6cz0J~&ZxyCk~AWN>lgfC-B=;Sjmd(GIP$hBJQ&plP<#>O!lNr)Mb!H<-|+AG~due~Mz z34q*kbl4wmNr>&76?!|+ZZpEjVjS^(QS8bazh_-(APNawl<*3no9Svv3v+H~=nO&} z$R|rN*$0byeVW9Xx({6*UpeKQ0`d^uIuUC#fT=VSg%RKGGM|w@De{iv!d()AXnj3D zlNZ6#bhe!JcRSz0&^hp%*GuWqw2?_ zzuOgjmY5Q!<+QtJh0AS&c{b3}8U;_Xdd#{$iE=}9=kGrS;2z|8pLg9~+}{PoTWvUN zZe_m&LWTueG}bas!=N0t0?XSI(iH&u^yJe8Q!tMi(h(F+*E0pkHQf%AvZ=fA$-V5c zvGgPl%Xw3oAHTpj0`M=uwhrTBT$IwU^9I&m^<;!cK!ITGv?ue(4Z~!hEYA${dONr% z?=}*M(Spa)oAN(D9@v4pHXVML63FgQHr|jW z6v#?#u7uEN4?V@G4zNE(w}dV_VZ8&f~mDWvywZJ+ttN%}3kI{$6*{%(kL zcp0`rs!*^Fh*slTr??fb9EcgUuAK5{E_PB^LX|MZYel!p$k9WfzpiRO8M#o%+KC0{b`p^&S;R##ioh)7K3=_SsQd`eNtcCM|q> z1kas-9`(Tbh$$QkSc8aW8$x} zz79@6DosRJCZJ#=om_qSt|r66SK?W37M&Z@t^j(xBJ$CL92?^6-o}LSk`{9dT+yp) ztt)3Pd(%2PD$X8#5|bX~dm9DPkv;5rP9M zK^H1jbnc`$vRyo;X2a(1i5{k$$#z^%4_o)X;o znwWwF!B0geWLvM`hTfYy9MFb$*`k8kV~_pSJq2)+#$9Xk+NZ?KTqU3~`L=KP*6HVI zWzdL2ZA##9CupS*8!Vd9(G!J`dmt}i7ri&8O8n`_$Z|Zer6~*?mG1DDc?o7#xy4cV{33LEy|Ols^4XG{UH^)Q*>sPV6``O(T^TqIMmUD9bnxwyyX%HNgJYuM&BrjL7t(ofSY)83dGJVqC33$g`Tclzj> zV5N83U9|Ie>{2ls=}dL~`%n-Ai}6Zhw{vm*y9Y5n zTi9#x3HAFU&7xOdbN;}&EBvcgYFZ9gwlt|ES`*`}u;#VqYN-(SQ~)Oc;)Vvqdh8TD ztZiBFXsK}6!@Le!7$c@teiQTWysvrDoU9S)lUX*-sEJO`H<1g9q0WuvGyQ4A`3d8I zq`@b8iHc29N#}+efEdN@Oz|aYlL#D_<(REl+bs#E=|h*=Gv;h-B~xXkFyF_A%D&J? zb1NWSE79IzP`uglu&WlF8q+jC3n)JCFUfc(^-F)G_`d9Tk%pZQaj3=8V5{d*LTI|n zC6)QbZwdohFsBIb8+=M2L;vL}X)`Ep&!j>+wfc^YW63$SKrBC=Q4Xo$lYPEhCu&4C zW|`art__PJ!>6VDS2D1&e_UE^;J)(IMlE{1(p)NA3VH&%6ptaeA4gmYzAEI>1nOz| zZI&?(=XtR6FI(c!exK#~@CaEnW_2kbq#DeW5_FwQ@+7o1TGMgF)Ow_&B6L~i$!V&s zT+Nn0SEmBApQhY9-le_j=messg<3nijU`Isb-B2U5o_C-!p+hhvVDF;=Jy#)EsEH( zds|y{W1z~8iEyqlL`IXTq5==qO=b)FgLa*P z?m=oPV0PVNy8zVSEQ^94o$WKC`b|~zvp*V^O;x}*!+dKzz>8`63GE2hcc|UFalg6aTu6Ac|En@X;U2_D52@^w{7yi1as0;vU`#1 z5RNO?BmDMf2%1e3^#NjG@8s^DQ!$*0uEo+uk}rQ57G~>&JJ(ZO)J>p@!#saSSD75y zHLaLqtl){?kwx$1`vXtLwygzk%FJMwA^A>qewQ|)s?s>avC!&UCit%~h0qoR^7gP5 z-!*W=XeE#-hiiLRoo_g>NCKTy^@KTOmP^)N154xywnwJaB0V;wrNUMdcwThxIf?#I zJ$Ikyh5Yl+F6*1z*tZ&RpMaL`FEImXrH|PbmVf%Z38!n(Tc) zz|r7zB&@gSX7-2zzV}nh(cM2olk#p_kX+Tlrz)toUC4%u-ewx7T?UrpKVp_qM$yys zQ%^r23#`KW>%%`+2<5^8;UTo1V`(ZbMD|@k39Z7D73BklQ(YTh1-)pQL8?BmY|wn{ z%$$DE%BKgXs^0^IVIEzob&kkS2TbQ+k3LWGkAtZ≫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�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 HeDQw(lBJ`W diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/related-entity-data-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/related-entity-data-ft.png index 1f8df2034c183591921120fa5ebac38dfe349f00..bbfcb112f99ebd100e1d096eae9cb3f8978414e5 100644 GIT binary patch literal 38232 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 g93?Vb{cB>E1E`prBD#du~8M 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 z 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 BWugE8 diff --git a/ui-ngx/src/assets/help/images/rulenode/examples/tenant-attributes-ft.png b/ui-ngx/src/assets/help/images/rulenode/examples/tenant-attributes-ft.png index fe32e45e572a3749d51846d4a924e122bf48ca2d..f2c96e82974b66e759c27a6f450887dbe408f9ea 100644 GIT binary patch literal 29138 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 Date: Wed, 27 Sep 2023 15:12:34 +0300 Subject: [PATCH 106/267] tbe: fix_bug Integer from Json to Long --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6eba036d51..02d610fd9f 100755 --- a/pom.xml +++ b/pom.xml @@ -78,7 +78,7 @@ 3.8.1 3.21.9 1.42.1 - 1.1.1 + 1.1.2 1.18.18 1.2.4 1.2.5 From 2755a21f950776a9ea3c4c2f2211321e1df7b592 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 28 Sep 2023 11:09:44 +0300 Subject: [PATCH 107/267] UI: Fixed translation on change lang --- ui-ngx/src/app/core/auth/auth.service.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/core/auth/auth.service.ts b/ui-ngx/src/app/core/auth/auth.service.ts index 1253184714..f4777aae29 100644 --- a/ui-ngx/src/app/core/auth/auth.service.ts +++ b/ui-ngx/src/app/core/auth/auth.service.ts @@ -424,8 +424,8 @@ export class AuthService { } else { userLang = null; } - this.notifyUserLang(userLang); loadUserSubject.next(authPayload); + this.notifyUserLang(userLang); loadUserSubject.complete(); }, (err) => { From 77745b58a12075c5af13aacc28dc2cf0194ce773 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 28 Sep 2023 12:37:23 +0300 Subject: [PATCH 108/267] UI: Refactoring dashboard detail button --- .../dashboard/dashboard-form.component.html | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html index 3514b0d919..0cb6adc7be 100644 --- a/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html +++ b/ui-ngx/src/app/modules/home/pages/dashboard/dashboard-form.component.html @@ -65,16 +65,16 @@ [fxShow]="!hideDelete() && !isEdit"> {{'dashboard.delete' | translate }} - -

Date: Thu, 28 Sep 2023 18:16:20 +0300 Subject: [PATCH 109/267] Implement widget types / bundles pagination and full text search. Add widget types tags. UI: Implement scroll grid component. --- .../main/data/upgrade/3.6.0/schema_update.sql | 18 + .../controller/WidgetTypeController.java | 54 ++- .../controller/WidgetsBundleController.java | 9 +- .../install/ThingsboardInstallService.java | 3 + .../constructor/WidgetTypeMsgConstructor.java | 5 + .../SystemWidgetTypesEdgeEventFetcher.java | 3 +- .../SystemWidgetsBundlesEdgeEventFetcher.java | 2 +- .../TenantWidgetTypesEdgeEventFetcher.java | 3 +- .../DefaultSystemDataLoaderService.java | 16 +- .../install/SqlDatabaseUpgradeService.java | 13 + .../server/dao/widget/WidgetTypeService.java | 9 +- .../dao/widget/WidgetsBundleService.java | 4 +- .../common/data/widget/DeprecatedFilter.java | 22 ++ .../common/data/widget/WidgetTypeDetails.java | 4 + .../common/data/widget/WidgetTypeInfo.java | 7 +- common/edge-api/src/main/proto/edge.proto | 1 + .../server/dao/model/ModelConstants.java | 5 + .../model/sql/WidgetTypeDetailsEntity.java | 8 + .../dao/model/sql/WidgetTypeInfoEntity.java | 34 +- .../dao/sql/widget/JpaWidgetTypeDao.java | 55 ++- .../dao/sql/widget/JpaWidgetsBundleDao.java | 49 ++- .../sql/widget/WidgetTypeInfoRepository.java | 134 +++++++ .../dao/sql/widget/WidgetTypeRepository.java | 31 -- .../sql/widget/WidgetsBundleRepository.java | 49 ++- .../dao/util/mapping/AbstractArrayType.java | 45 +++ .../mapping/AbstractArrayTypeDescriptor.java | 119 +++++++ .../util/mapping/ArraySqlTypeDescriptor.java | 86 +++++ .../server/dao/util/mapping/ArrayUtil.java | 335 ++++++++++++++++++ .../mapping/ParameterizedParameterType.java | 64 ++++ .../dao/util/mapping/StringArrayType.java | 41 +++ .../mapping/StringArrayTypeDescriptor.java | 31 ++ .../server/dao/widget/WidgetTypeDao.java | 16 +- .../dao/widget/WidgetTypeServiceImpl.java | 32 +- .../server/dao/widget/WidgetsBundleDao.java | 4 +- .../dao/widget/WidgetsBundleServiceImpl.java | 16 +- .../main/resources/sql/schema-entities.sql | 1 + .../sql/schema-views-and-functions.sql | 6 + .../dao/service/WidgetsBundleServiceTest.java | 8 +- .../dao/sql/widget/JpaWidgetTypeDaoTest.java | 67 +++- .../sql/widget/JpaWidgetsBundleDaoTest.java | 137 ++++++- ui-ngx/src/app/core/http/entity.service.ts | 2 +- ui-ngx/src/app/core/http/widget.service.ts | 61 ++-- .../dashboard-page.component.html | 43 ++- .../dashboard-page.component.ts | 13 +- .../dashboard-widget-select.component.html | 128 ++++--- .../dashboard-widget-select.component.scss | 126 +++---- .../dashboard-widget-select.component.ts | 307 ++++++++-------- .../grid/scroll-grid.component.html | 53 +++ .../grid/scroll-grid.component.scss | 32 ++ .../components/grid/scroll-grid.component.ts | 103 ++++++ .../home/components/home-components.module.ts | 7 +- .../datasource/scroll-grid-datasource.ts | 250 +++++++++++++ .../home/models/widget-component.models.ts | 3 + .../pages/widget/widget-editor.component.html | 5 + .../widget/widget-library-routing.module.ts | 2 +- .../pages/widget/widget-type.component.html | 4 + .../pages/widget/widget-type.component.ts | 2 + .../widgets-bundle-widgets.component.ts | 2 +- ui-ngx/src/app/shared/models/widget.models.ts | 8 + .../assets/locale/locale.constant-en_US.json | 1 + 60 files changed, 2222 insertions(+), 476 deletions(-) create mode 100644 application/src/main/data/upgrade/3.6.0/schema_update.sql create mode 100644 common/data/src/main/java/org/thingsboard/server/common/data/widget/DeprecatedFilter.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayType.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java create mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java create mode 100644 ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.html create mode 100644 ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts create mode 100644 ui-ngx/src/app/modules/home/models/datasource/scroll-grid-datasource.ts diff --git a/application/src/main/data/upgrade/3.6.0/schema_update.sql b/application/src/main/data/upgrade/3.6.0/schema_update.sql new file mode 100644 index 0000000000..dd07a47dac --- /dev/null +++ b/application/src/main/data/upgrade/3.6.0/schema_update.sql @@ -0,0 +1,18 @@ +-- +-- Copyright © 2016-2023 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. +-- + +ALTER TABLE widget_type + ADD COLUMN IF NOT EXISTS tags text[]; \ No newline at end of file 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 4aeaeb2210..f90a196edf 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetTypeController.java @@ -28,6 +28,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.server.common.data.StringUtils; import org.thingsboard.server.common.data.exception.ThingsboardErrorCode; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; @@ -36,6 +37,7 @@ import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; @@ -46,6 +48,8 @@ import org.thingsboard.server.service.entitiy.widgets.type.TbWidgetTypeService; import org.thingsboard.server.service.security.permission.Operation; import org.thingsboard.server.service.security.permission.Resource; +import java.util.Arrays; +import java.util.Collections; import java.util.List; import static org.thingsboard.server.controller.ControllerConstants.AVAILABLE_FOR_ANY_AUTHORIZED_USER; @@ -75,7 +79,11 @@ public class WidgetTypeController extends AutoCommitController { private static final String WIDGET_TYPE_INFO_DESCRIPTION = "Widget Type Info is a lightweight object that represents Widget Type but does not contain the heavyweight widget descriptor JSON"; private static final String TENANT_ONLY_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether only tenant widget types should be returned"; private static final String FULL_SEARCH_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether search widgets by description not only by name"; + private static final String DEPRECATED_FILTER_ALLOWABLE_VALUES = "ALL, ACTUAL, DEPRECATED"; + private static final String DEPRECATED_FILTER_PARAM_DESCRIPTION = "Optional string parameter indicating whether to include deprecated widgets"; private static final String UPDATE_EXISTING_BY_FQN_PARAM_DESCRIPTION = "Optional boolean parameter indicating whether to update existing widget type by FQN if present instead of creating new one"; + private static final String WIDGET_TYPE_ARRAY_DESCRIPTION = "A list of string values separated by comma ',' representing one of the widget type value"; + private static final String WIDGET_TYPE_ALLOWABLE_VALUES = "timeseries, latest, control, alarm, static"; @ApiOperation(value = "Get Widget Type Details (getWidgetTypeById)", notes = "Get the Widget Type Details based on the provided Widget Type Id. " + WIDGET_TYPE_DETAILS_DESCRIPTION + SYSTEM_OR_TENANT_AUTHORITY_PARAGRAPH) @@ -166,15 +174,22 @@ public class WidgetTypeController extends AutoCommitController { @ApiParam(value = TENANT_ONLY_PARAM_DESCRIPTION) @RequestParam(required = false) Boolean tenantOnly, @ApiParam(value = FULL_SEARCH_PARAM_DESCRIPTION) - @RequestParam(required = false) Boolean fullSearch) throws ThingsboardException { + @RequestParam(required = false) Boolean fullSearch, + @ApiParam(value = DEPRECATED_FILTER_PARAM_DESCRIPTION, allowableValues = DEPRECATED_FILTER_ALLOWABLE_VALUES) + @RequestParam(required = false) String deprecatedFilter, + @ApiParam(value = WIDGET_TYPE_ARRAY_DESCRIPTION, allowableValues = WIDGET_TYPE_ALLOWABLE_VALUES) + @RequestParam(required = false) String[] widgetTypeList) throws ThingsboardException { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); + List widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList(); + boolean fullSearchBool = fullSearch != null && fullSearch; + DeprecatedFilter widgetTypeDeprecatedFilter = StringUtils.isNotEmpty(deprecatedFilter) ? DeprecatedFilter.valueOf(deprecatedFilter) : DeprecatedFilter.ALL; if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { - return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink)); + return checkNotNull(widgetTypeService.findSystemWidgetTypesByPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); } else { if (tenantOnly != null && tenantOnly) { - return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink)); + return checkNotNull(widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); } else { - return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink)); + return checkNotNull(widgetTypeService.findAllTenantWidgetTypesByTenantIdAndPageLink(getTenantId(), fullSearchBool, widgetTypeDeprecatedFilter, widgetTypes, pageLink)); } } } @@ -272,19 +287,40 @@ public class WidgetTypeController extends AutoCommitController { tenantId = getCurrentUser().getTenantId(); } WidgetsBundle widgetsBundle = checkNotNull(widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(tenantId, bundleAlias)); - return checkNotNull(widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(getTenantId(), widgetsBundle.getId())); + return checkNotNull(widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(getTenantId(), widgetsBundle.getId(), false, DeprecatedFilter.ALL, + null, new PageLink(1024))).getData(); } @ApiOperation(value = "Get Widget Type Info objects (getBundleWidgetTypesInfos)", notes = "Get the Widget Type Info objects based on the provided parameters. " + WIDGET_TYPE_INFO_DESCRIPTION + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN', 'CUSTOMER_USER')") - @RequestMapping(value = "/widgetTypesInfos", params = {"widgetsBundleId"}, method = RequestMethod.GET) + @RequestMapping(value = "/widgetTypesInfos", params = {"widgetsBundleId", "pageSize", "page"}, method = RequestMethod.GET) @ResponseBody - public List getBundleWidgetTypesInfos( + public PageData getBundleWidgetTypesInfos( @ApiParam(value = "Widget Bundle Id", required = true) - @RequestParam("widgetsBundleId") String strWidgetsBundleId) throws ThingsboardException { + @RequestParam("widgetsBundleId") String strWidgetsBundleId, + @ApiParam(value = PAGE_SIZE_DESCRIPTION, required = true) + @RequestParam int pageSize, + @ApiParam(value = PAGE_NUMBER_DESCRIPTION, required = true) + @RequestParam int page, + @ApiParam(value = WIDGET_TYPE_TEXT_SEARCH_DESCRIPTION) + @RequestParam(required = false) String textSearch, + @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = WIDGET_TYPE_SORT_PROPERTY_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortProperty, + @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) + @RequestParam(required = false) String sortOrder, + @ApiParam(value = FULL_SEARCH_PARAM_DESCRIPTION) + @RequestParam(required = false) Boolean fullSearch, + @ApiParam(value = DEPRECATED_FILTER_PARAM_DESCRIPTION, allowableValues = DEPRECATED_FILTER_ALLOWABLE_VALUES) + @RequestParam(required = false) String deprecatedFilter, + @ApiParam(value = WIDGET_TYPE_ARRAY_DESCRIPTION, allowableValues = WIDGET_TYPE_ALLOWABLE_VALUES) + @RequestParam(required = false) String[] widgetTypeList) throws ThingsboardException { WidgetsBundleId widgetsBundleId = new WidgetsBundleId(toUUID(strWidgetsBundleId)); - return checkNotNull(widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(getTenantId(), widgetsBundleId)); + PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); + List widgetTypes = widgetTypeList != null ? Arrays.asList(widgetTypeList) : Collections.emptyList(); + DeprecatedFilter widgetTypeDeprecatedFilter = StringUtils.isNotEmpty(deprecatedFilter) ? DeprecatedFilter.valueOf(deprecatedFilter) : DeprecatedFilter.ALL; + return checkNotNull(widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(getTenantId(), widgetsBundleId, fullSearch != null && fullSearch, + widgetTypeDeprecatedFilter, widgetTypes, pageLink)); } @ApiOperation(value = "Get Widget Type (getWidgetTypeByBundleAliasAndTypeAlias) (Deprecated)", 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 382546dc96..b07467b94b 100644 --- a/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java +++ b/application/src/main/java/org/thingsboard/server/controller/WidgetsBundleController.java @@ -68,6 +68,7 @@ public class WidgetsBundleController extends BaseController { private final TbWidgetsBundleService tbWidgetsBundleService; private static final String WIDGET_BUNDLE_DESCRIPTION = "Widget Bundle represents a group(bundle) of widgets. Widgets are grouped into bundle by type or use case. "; + private static final String FULL_SEARCH_PARAM_DESCRIPTION = "Optional boolean parameter indicating extended search of widget bundles by description and by name / description of related widget types"; @ApiOperation(value = "Get Widget Bundle (getWidgetsBundleById)", notes = "Get the Widget Bundle based on the provided Widget Bundle Id. " + WIDGET_BUNDLE_DESCRIPTION + AVAILABLE_FOR_ANY_AUTHORIZED_USER) @@ -183,13 +184,15 @@ public class WidgetsBundleController extends BaseController { @ApiParam(value = SORT_PROPERTY_DESCRIPTION, allowableValues = WIDGET_BUNDLE_SORT_PROPERTY_ALLOWABLE_VALUES) @RequestParam(required = false) String sortProperty, @ApiParam(value = SORT_ORDER_DESCRIPTION, allowableValues = SORT_ORDER_ALLOWABLE_VALUES) - @RequestParam(required = false) String sortOrder) throws ThingsboardException { + @RequestParam(required = false) String sortOrder, + @ApiParam(value = FULL_SEARCH_PARAM_DESCRIPTION) + @RequestParam(required = false) Boolean fullSearch) throws ThingsboardException { PageLink pageLink = createPageLink(pageSize, page, textSearch, sortProperty, sortOrder); if (Authority.SYS_ADMIN.equals(getCurrentUser().getAuthority())) { - return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), pageLink)); + return checkNotNull(widgetsBundleService.findSystemWidgetsBundlesByPageLink(getTenantId(), fullSearch != null && fullSearch, pageLink)); } else { TenantId tenantId = getCurrentUser().getTenantId(); - return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink)); + return checkNotNull(widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, fullSearch != null && fullSearch, pageLink)); } } 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 208da7d36c..3829b3cf45 100644 --- a/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java +++ b/application/src/main/java/org/thingsboard/server/install/ThingsboardInstallService.java @@ -262,6 +262,9 @@ public class ThingsboardInstallService { databaseEntitiesUpgradeService.upgradeDatabase("3.5.1"); dataUpdateService.updateData("3.5.1"); systemDataLoaderService.updateDefaultNotificationConfigs(); + case "3.6.0": + log.info("Upgrading ThingsBoard from version 3.6.0 to 3.6.1 ..."); + databaseEntitiesUpgradeService.upgradeDatabase("3.6.0"); //TODO DON'T FORGET to update switch statement in the CacheCleanupService if you need to clear the cache break; default: 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 af574b4b75..e6f04261fb 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 @@ -24,6 +24,8 @@ import org.thingsboard.server.gen.edge.v1.UpdateMsgType; import org.thingsboard.server.gen.edge.v1.WidgetTypeUpdateMsg; import org.thingsboard.server.queue.util.TbCoreComponent; +import java.util.Arrays; + @Component @TbCoreComponent public class WidgetTypeMsgConstructor { @@ -59,6 +61,9 @@ public class WidgetTypeMsgConstructor { builder.setDescription(widgetTypeDetails.getDescription()); } builder.setDeprecated(widgetTypeDetails.isDeprecated()); + if (widgetTypeDetails.getTags() != null) { + builder.addAllTags(Arrays.asList(widgetTypeDetails.getTags())); + } return builder.build(); } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java index de4218fc53..4bb4d1fb06 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetTypesEdgeEventFetcher.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; 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.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.widget.WidgetTypeService; @@ -31,6 +32,6 @@ public class SystemWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF @Override protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) { - return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, false, pageLink); + return widgetTypeService.findSystemWidgetTypesByPageLink(tenantId, false, DeprecatedFilter.ALL, null, pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java index 87cffcee9f..d1ee0723dd 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/SystemWidgetsBundlesEdgeEventFetcher.java @@ -31,6 +31,6 @@ public class SystemWidgetsBundlesEdgeEventFetcher extends BaseWidgetsBundlesEdge @Override protected PageData findWidgetsBundles(TenantId tenantId, PageLink pageLink) { - return widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, pageLink); + return widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, false, pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java index 24f0527c20..85e23427d3 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/fetch/TenantWidgetTypesEdgeEventFetcher.java @@ -19,6 +19,7 @@ import lombok.extern.slf4j.Slf4j; 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.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.widget.WidgetTypeService; @@ -30,6 +31,6 @@ public class TenantWidgetTypesEdgeEventFetcher extends BaseWidgetTypesEdgeEventF } @Override protected PageData findWidgetTypes(TenantId tenantId, PageLink pageLink) { - return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, false, pageLink); + return widgetTypeService.findTenantWidgetTypesByTenantIdAndPageLink(tenantId, false, DeprecatedFilter.ALL, null, pageLink); } } diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 4bb3645f20..29dcd601a1 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -63,6 +63,7 @@ import org.thingsboard.server.common.data.kv.BasicTsKvEntry; import org.thingsboard.server.common.data.kv.BooleanDataEntry; import org.thingsboard.server.common.data.kv.DoubleDataEntry; import org.thingsboard.server.common.data.kv.LongDataEntry; +import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageDataIterable; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.query.BooleanFilterPredicate; @@ -83,6 +84,8 @@ import org.thingsboard.server.common.data.security.UserCredentials; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; +import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.common.data.widget.WidgetsBundle; import org.thingsboard.server.dao.attributes.AttributesService; import org.thingsboard.server.dao.customer.CustomerService; @@ -489,10 +492,15 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { public void deleteSystemWidgetBundle(String bundleAlias) throws Exception { WidgetsBundle widgetsBundle = widgetsBundleService.findWidgetsBundleByTenantIdAndAlias(TenantId.SYS_TENANT_ID, bundleAlias); if (widgetsBundle != null) { - var widgetTypes = widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID, widgetsBundle.getId()); - for (var widgetType : widgetTypes) { - widgetTypeService.deleteWidgetType(TenantId.SYS_TENANT_ID, widgetType.getId()); - } + PageData widgetTypes; + var pageLink = new PageLink(1024); + do { + widgetTypes = widgetTypeService.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID, widgetsBundle.getId(), false, DeprecatedFilter.ALL, null, pageLink); + for (var widgetType : widgetTypes.getData()) { + widgetTypeService.deleteWidgetType(TenantId.SYS_TENANT_ID, widgetType.getId()); + } + pageLink.nextPageLink(); + } while (widgetTypes.hasNext()); widgetsBundleService.deleteWidgetsBundle(TenantId.SYS_TENANT_ID, widgetsBundle.getId()); } } 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 307e2e5f3a..908fc75ec6 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 @@ -777,6 +777,19 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService log.error("Failed updating schema!!!", e); } break; + case "3.6.0": + try (Connection conn = DriverManager.getConnection(dbUrl, dbUserName, dbPassword)) { + log.info("Updating schema ..."); + if (isOldSchema(conn, 3006000)) { + schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.6.0", SCHEMA_UPDATE_SQL); + loadSql(schemaUpdateFile, conn); + conn.createStatement().execute("UPDATE tb_schema_settings SET schema_version = 3006001;"); + } + 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/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java index edc6bb21da..d8df5d61a3 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeService.java @@ -20,6 +20,7 @@ import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; @@ -39,17 +40,17 @@ public interface WidgetTypeService extends EntityDaoService { void deleteWidgetType(TenantId tenantId, WidgetTypeId widgetTypeId); - PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink); + PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); - PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink); + PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); - PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink); + PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); List findWidgetTypesByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); List findWidgetTypesDetailsByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); - List findWidgetTypesInfosByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); + PageData findWidgetTypesInfosByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); List findWidgetFqnsByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId); diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java index e350846881..15fd4838dd 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleService.java @@ -34,13 +34,13 @@ public interface WidgetsBundleService extends EntityDaoService { WidgetsBundle findWidgetsBundleByTenantIdAndAlias(TenantId tenantId, String alias); - PageData findSystemWidgetsBundlesByPageLink(TenantId tenantId, PageLink pageLink); + PageData findSystemWidgetsBundlesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink); List findSystemWidgetsBundles(TenantId tenantId); PageData findTenantWidgetsBundlesByTenantId(TenantId tenantId, PageLink pageLink); - PageData findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink); + PageData findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink); List findAllTenantWidgetsBundlesByTenantId(TenantId tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/DeprecatedFilter.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/DeprecatedFilter.java new file mode 100644 index 0000000000..8ceb0d48a9 --- /dev/null +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/DeprecatedFilter.java @@ -0,0 +1,22 @@ +/** + * Copyright © 2016-2023 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.widget; + +public enum DeprecatedFilter { + ALL, + ACTUAL, + DEPRECATED +} diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java index cd6f13c6d0..424e0bc6bc 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeDetails.java @@ -38,6 +38,9 @@ public class WidgetTypeDetails extends WidgetType implements HasName, HasTenantI @Length(fieldName = "description", max = 1024) @ApiModelProperty(position = 10, value = "Description of the widget") private String description; + @NoXss + @ApiModelProperty(position = 11, value = "Tags of the widget type") + private String[] tags; @Getter @Setter @@ -59,6 +62,7 @@ public class WidgetTypeDetails extends WidgetType implements HasName, HasTenantI super(widgetTypeDetails); this.image = widgetTypeDetails.getImage(); this.description = widgetTypeDetails.getDescription(); + this.tags = widgetTypeDetails.getTags(); this.externalId = widgetTypeDetails.getExternalId(); } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java index 0e8bce0a19..3387fb13b6 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/widget/WidgetTypeInfo.java @@ -29,7 +29,10 @@ public class WidgetTypeInfo extends BaseWidgetType { @ApiModelProperty(position = 9, value = "Description of the widget type", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private String description; @NoXss - @ApiModelProperty(position = 10, value = "Type of the widget (timeseries, latest, control, alarm or static)", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + @ApiModelProperty(position = 10, value = "Tags of the widget type", accessMode = ApiModelProperty.AccessMode.READ_ONLY) + private String[] tags; + @NoXss + @ApiModelProperty(position = 11, value = "Type of the widget (timeseries, latest, control, alarm or static)", accessMode = ApiModelProperty.AccessMode.READ_ONLY) private String widgetType; public WidgetTypeInfo() { @@ -48,6 +51,7 @@ public class WidgetTypeInfo extends BaseWidgetType { super(widgetTypeInfo); this.image = widgetTypeInfo.getImage(); this.description = widgetTypeInfo.getDescription(); + this.tags = widgetTypeInfo.getTags(); this.widgetType = widgetTypeInfo.getWidgetType(); } @@ -55,6 +59,7 @@ public class WidgetTypeInfo extends BaseWidgetType { super(widgetTypeDetails); this.image = widgetTypeDetails.getImage(); this.description = widgetTypeDetails.getDescription(); + this.tags = widgetTypeDetails.getTags(); if (widgetTypeDetails.getDescriptor() != null && widgetTypeDetails.getDescriptor().has("type")) { this.widgetType = widgetTypeDetails.getDescriptor().get("type").asText(); } else { diff --git a/common/edge-api/src/main/proto/edge.proto b/common/edge-api/src/main/proto/edge.proto index b316d5b3c4..bc0170b24b 100644 --- a/common/edge-api/src/main/proto/edge.proto +++ b/common/edge-api/src/main/proto/edge.proto @@ -377,6 +377,7 @@ message WidgetTypeUpdateMsg { optional string description = 10; optional string fqn = 11; bool deprecated = 12; + repeated string tags = 13; } message AdminSettingsUpdateMsg { 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 0e8ea2db15..d27a5365ef 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 @@ -313,10 +313,15 @@ public class ModelConstants { public static final String WIDGET_TYPE_NAME_PROPERTY = "name"; public static final String WIDGET_TYPE_IMAGE_PROPERTY = "image"; public static final String WIDGET_TYPE_DESCRIPTION_PROPERTY = "description"; + public static final String WIDGET_TYPE_TAGS_PROPERTY = "tags"; public static final String WIDGET_TYPE_DESCRIPTOR_PROPERTY = "descriptor"; public static final String WIDGET_TYPE_DEPRECATED_PROPERTY = "deprecated"; + public static final String WIDGET_TYPE_WIDGET_TYPE_PROPERTY = "widget_type"; + + public static final String WIDGET_TYPE_INFO_VIEW_TABLE_NAME = "widget_type_info_view"; + /** * Widgets bundle widget constants. */ diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java index be934e9c8f..99555393c6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java @@ -26,6 +26,7 @@ import org.thingsboard.server.common.data.widget.BaseWidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.util.mapping.JsonStringType; +import org.thingsboard.server.dao.util.mapping.StringArrayType; import javax.persistence.Column; import javax.persistence.Entity; @@ -36,6 +37,7 @@ import java.util.UUID; @EqualsAndHashCode(callSuper = true) @Entity @TypeDef(name = "json", typeClass = JsonStringType.class) +@TypeDef(name = "string-array", typeClass = StringArrayType.class) @Table(name = ModelConstants.WIDGET_TYPE_TABLE_NAME) public class WidgetTypeDetailsEntity extends AbstractWidgetTypeEntity { @@ -45,6 +47,10 @@ public class WidgetTypeDetailsEntity extends AbstractWidgetTypeEntity { + @Column(name = ModelConstants.WIDGET_TYPE_IMAGE_PROPERTY) private String image; + + @Column(name = ModelConstants.WIDGET_TYPE_DESCRIPTION_PROPERTY) private String description; + + @Type(type="string-array") + @Column(name = ModelConstants.WIDGET_TYPE_TAGS_PROPERTY, columnDefinition = "text[]") + private String[] tags; + + @Column(name = ModelConstants.WIDGET_TYPE_WIDGET_TYPE_PROPERTY) private String widgetType; public WidgetTypeInfoEntity() { super(); } - public WidgetTypeInfoEntity(WidgetTypeDetailsEntity widgetTypeDetailsEntity) { - super(widgetTypeDetailsEntity); - this.image = widgetTypeDetailsEntity.getImage(); - this.description = widgetTypeDetailsEntity.getDescription(); - if (widgetTypeDetailsEntity.getDescriptor() != null && widgetTypeDetailsEntity.getDescriptor().has("type")) { - this.widgetType = widgetTypeDetailsEntity.getDescriptor().get("type").asText(); - } else { - this.widgetType = ""; - } - } - @Override public WidgetTypeInfo toData() { BaseWidgetType baseWidgetType = super.toBaseWidgetType(); WidgetTypeInfo widgetTypeInfo = new WidgetTypeInfo(baseWidgetType); widgetTypeInfo.setImage(image); widgetTypeInfo.setDescription(description); + widgetTypeInfo.setTags(tags); widgetTypeInfo.setWidgetType(widgetType); return widgetTypeInfo; } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index 0548ad814d..1d446be1b3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -23,6 +23,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; @@ -35,6 +36,7 @@ import org.thingsboard.server.dao.sql.JpaAbstractDao; import org.thingsboard.server.dao.util.SqlDao; import org.thingsboard.server.dao.widget.WidgetTypeDao; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Objects; @@ -54,6 +56,9 @@ public class JpaWidgetTypeDao extends JpaAbstractDao findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, PageLink pageLink) { + public PageData findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); + boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); return DaoUtil.toPageData( - widgetTypeRepository + widgetTypeInfoRepository .findSystemWidgetTypes( NULL_UUID, Objects.toString(pageLink.getTextSearch(), ""), fullSearch, + deprecatedFilterEnabled, + deprecatedFilterBool, + widgetTypesEmpty, + widgetTypes == null ? Collections.emptyList() : widgetTypes, DaoUtil.toPageable(pageLink))); } @Override - public PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink) { + public PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); + boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); return DaoUtil.toPageData( - widgetTypeRepository + widgetTypeInfoRepository .findAllTenantWidgetTypesByTenantId( tenantId, NULL_UUID, Objects.toString(pageLink.getTextSearch(), ""), fullSearch, + deprecatedFilterEnabled, + deprecatedFilterBool, + widgetTypesEmpty, + widgetTypes == null ? Collections.emptyList() : widgetTypes, DaoUtil.toPageable(pageLink))); } @Override - public PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink) { + public PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); + boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); return DaoUtil.toPageData( - widgetTypeRepository + widgetTypeInfoRepository .findTenantWidgetTypesByTenantId( tenantId, Objects.toString(pageLink.getTextSearch(), ""), fullSearch, + deprecatedFilterEnabled, + deprecatedFilterBool, + widgetTypesEmpty, + widgetTypes == null ? Collections.emptyList() : widgetTypes, DaoUtil.toPageable(pageLink))); } @@ -122,8 +148,21 @@ public class JpaWidgetTypeDao extends JpaAbstractDao findWidgetTypesInfosByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId) { - return DaoUtil.convertDataList(widgetTypeRepository.findWidgetTypesInfosByWidgetsBundleId(widgetsBundleId)); + public PageData findWidgetTypesInfosByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + boolean deprecatedFilterEnabled = !DeprecatedFilter.ALL.equals(deprecatedFilter); + boolean deprecatedFilterBool = DeprecatedFilter.DEPRECATED.equals(deprecatedFilter); + boolean widgetTypesEmpty = widgetTypes == null || widgetTypes.isEmpty(); + return DaoUtil.toPageData( + widgetTypeInfoRepository + .findWidgetTypesInfosByWidgetsBundleId( + widgetsBundleId, + Objects.toString(pageLink.getTextSearch(), ""), + fullSearch, + deprecatedFilterEnabled, + deprecatedFilterBool, + widgetTypesEmpty, + widgetTypes == null ? Collections.emptyList() : widgetTypes, + DaoUtil.toPageable(pageLink))); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java index f3a476d8eb..e9c972c7a3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java @@ -62,13 +62,22 @@ public class JpaWidgetsBundleDao extends JpaAbstractDao findSystemWidgetsBundles(TenantId tenantId, PageLink pageLink) { - return DaoUtil.toPageData( - widgetsBundleRepository - .findSystemWidgetsBundles( - NULL_UUID, - Objects.toString(pageLink.getTextSearch(), ""), - DaoUtil.toPageable(pageLink))); + public PageData findSystemWidgetsBundles(TenantId tenantId, boolean fullSearch, PageLink pageLink) { + if (fullSearch) { + return DaoUtil.toPageData( + widgetsBundleRepository + .findSystemWidgetsBundlesFullSearch( + NULL_UUID, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } else { + return DaoUtil.toPageData( + widgetsBundleRepository + .findSystemWidgetsBundles( + NULL_UUID, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } } @Override @@ -82,14 +91,24 @@ public class JpaWidgetsBundleDao extends JpaAbstractDao findAllTenantWidgetsBundlesByTenantId(UUID tenantId, PageLink pageLink) { - return DaoUtil.toPageData( - widgetsBundleRepository - .findAllTenantWidgetsBundlesByTenantId( - tenantId, - NULL_UUID, - Objects.toString(pageLink.getTextSearch(), ""), - DaoUtil.toPageable(pageLink))); + public PageData findAllTenantWidgetsBundlesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink) { + if (fullSearch) { + return DaoUtil.toPageData( + widgetsBundleRepository + .findAllTenantWidgetsBundlesByTenantIdFullSearch( + tenantId, + NULL_UUID, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } else { + return DaoUtil.toPageData( + widgetsBundleRepository + .findAllTenantWidgetsBundlesByTenantId( + tenantId, + NULL_UUID, + Objects.toString(pageLink.getTextSearch(), ""), + DaoUtil.toPageable(pageLink))); + } } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java new file mode 100644 index 0000000000..27f4ef918f --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java @@ -0,0 +1,134 @@ +/** + * Copyright © 2016-2023 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.widget; + +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.query.Param; +import org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity; + +import java.util.List; +import java.util.UUID; + +public interface WidgetTypeInfoRepository extends JpaRepository { + + @Query(nativeQuery = true, + value = "SELECT * FROM widget_type_info_view wti WHERE wti.tenant_id = :systemTenantId " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))", + // "OR to_tsvector(lower(array_to_string(wti.tags, ' '))) @@ to_tsquery(lower(:searchText)))))", + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :systemTenantId " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))" + ) + Page findSystemWidgetTypes(@Param("systemTenantId") UUID systemTenantId, + @Param("searchText") String searchText, + @Param("fullSearch") boolean fullSearch, + @Param("deprecatedFilterEnabled") boolean deprecatedFilterEnabled, + @Param("deprecatedFilter") boolean deprecatedFilter, + @Param("widgetTypesEmpty") boolean widgetTypesEmpty, + @Param("widgetTypes") List widgetTypes, + Pageable pageable); + + @Query(nativeQuery = true, + value = "SELECT * FROM widget_type_info_view wti WHERE wti.tenant_id IN (:tenantId, :nullTenantId) " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))", + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id IN (:tenantId, :nullTenantId) " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))" + ) + Page findAllTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId, + @Param("nullTenantId") UUID nullTenantId, + @Param("searchText") String searchText, + @Param("fullSearch") boolean fullSearch, + @Param("deprecatedFilterEnabled") boolean deprecatedFilterEnabled, + @Param("deprecatedFilter") boolean deprecatedFilter, + @Param("widgetTypesEmpty") boolean widgetTypesEmpty, + @Param("widgetTypes") List widgetTypes, + Pageable pageable); + + @Query(nativeQuery = true, + value = "SELECT * FROM widget_type_info_view wti WHERE wti.tenant_id = :tenantId " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))", + countQuery = "SELECT count(*) FROM widget_type_info_view wti WHERE wti.tenant_id = :tenantId " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))" + ) + Page findTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId, + @Param("searchText") String searchText, + @Param("fullSearch") boolean fullSearch, + @Param("deprecatedFilterEnabled") boolean deprecatedFilterEnabled, + @Param("deprecatedFilter") boolean deprecatedFilter, + @Param("widgetTypesEmpty") boolean widgetTypesEmpty, + @Param("widgetTypes") List widgetTypes, + Pageable pageable); + + @Query("SELECT wti FROM WidgetTypeInfoEntity wti, WidgetsBundleWidgetEntity wbw " + + "WHERE wbw.widgetsBundleId = :widgetsBundleId " + + "AND wbw.widgetTypeId = wti.id ORDER BY wbw.widgetTypeOrder") + List findWidgetTypesInfosByWidgetsBundleId(@Param("widgetsBundleId") UUID widgetsBundleId); + + @Query(nativeQuery = true, + value = "SELECT * FROM widget_type_info_view wti, widgets_bundle_widget wbw " + + "WHERE wbw.widgets_bundle_id = :widgetsBundleId " + + "AND wbw.widget_type_id = wti.id " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' ')))) " + + "ORDER BY wbw.widget_type_order", + countQuery = "SELECT count(*) FROM widget_type_info_view wti, widgets_bundle_widget wbw " + + "WHERE wbw.widgets_bundle_id = :widgetsBundleId " + + "AND wbw.widget_type_id = wti.id " + + "AND ((:deprecatedFilterEnabled) IS FALSE OR wti.deprecated = :deprecatedFilter) " + + "AND ((:widgetTypesEmpty) IS TRUE OR wti.widget_type IN (:widgetTypes)) " + + "AND (wti.name ILIKE CONCAT('%', :searchText, '%') " + + "OR ((:fullSearch) IS TRUE AND (wti.description ILIKE CONCAT('%', :searchText, '%') " + + "OR lower(wti.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:searchText), ' '))))" + ) + Page findWidgetTypesInfosByWidgetsBundleId(@Param("widgetsBundleId") UUID widgetsBundleId, + @Param("searchText") String searchText, + @Param("fullSearch") boolean fullSearch, + @Param("deprecatedFilterEnabled") boolean deprecatedFilterEnabled, + @Param("deprecatedFilter") boolean deprecatedFilter, + @Param("widgetTypesEmpty") boolean widgetTypesEmpty, + @Param("widgetTypes") List widgetTypes, + Pageable pageable); + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java index 41fa293dd5..3c95cdb1f4 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeRepository.java @@ -24,8 +24,6 @@ import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.model.sql.WidgetTypeDetailsEntity; import org.thingsboard.server.dao.model.sql.WidgetTypeEntity; import org.thingsboard.server.dao.model.sql.WidgetTypeIdFqnEntity; -import org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity; -import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity; import java.util.List; import java.util.UUID; @@ -37,31 +35,6 @@ public interface WidgetTypeRepository extends JpaRepository findSystemWidgetTypes(@Param("systemTenantId") UUID systemTenantId, - @Param("searchText") String searchText, - @Param("fullSearch") boolean fullSearch, - Pageable pageable); - - @Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId IN (:tenantId, :nullTenantId) " + - "AND (LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - "OR ((:fullSearch) IS TRUE AND LOWER(wtd.description) LIKE LOWER(CONCAT('%', :searchText, '%'))))") - Page findAllTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId, - @Param("nullTenantId") UUID nullTenantId, - @Param("searchText") String searchText, - @Param("fullSearch") boolean fullSearch, - Pageable pageable); - - @Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId = :tenantId " + - "AND (LOWER(wtd.name) LIKE LOWER(CONCAT('%', :searchText, '%')) " + - "OR ((:fullSearch) IS TRUE AND LOWER(wtd.description) LIKE LOWER(CONCAT('%', :searchText, '%'))))") - Page findTenantWidgetTypesByTenantId(@Param("tenantId") UUID tenantId, - @Param("searchText") String searchText, - @Param("fullSearch") boolean fullSearch, - Pageable pageable); - @Query("SELECT wtd FROM WidgetTypeDetailsEntity wtd WHERE wtd.tenantId = :tenantId " + "AND LOWER(wtd.name) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findTenantWidgetTypeDetailsByTenantId(@Param("tenantId") UUID tenantId, @@ -78,10 +51,6 @@ public interface WidgetTypeRepository extends JpaRepository findWidgetTypesDetailsByWidgetsBundleId(@Param("widgetsBundleId") UUID widgetsBundleId); - @Query("SELECT new org.thingsboard.server.dao.model.sql.WidgetTypeInfoEntity(wtd) FROM WidgetTypeDetailsEntity wtd, WidgetsBundleWidgetEntity wbw " + - "WHERE wbw.widgetsBundleId = :widgetsBundleId " + - "AND wbw.widgetTypeId = wtd.id ORDER BY wbw.widgetTypeOrder") - List findWidgetTypesInfosByWidgetsBundleId(@Param("widgetsBundleId") UUID widgetsBundleId); @Query("SELECT wtd.fqn FROM WidgetTypeDetailsEntity wtd, WidgetsBundleWidgetEntity wbw " + "WHERE wbw.widgetsBundleId = :widgetsBundleId " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index 7a6ba68a36..25053bbbe6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -33,11 +33,33 @@ public interface WidgetsBundleRepository extends JpaRepository findSystemWidgetsBundles(@Param("systemTenantId") UUID systemTenantId, - @Param("searchText") String searchText, + @Param("textSearch") String textSearch, Pageable pageable); + @Query(nativeQuery = true, + value = "SELECT * FROM widgets_bundle wb WHERE wb.tenant_id = :systemTenantId " + + "AND (wb.title ILIKE CONCAT('%', :textSearch, '%') " + + "OR wb.description ILIKE CONCAT('%', :textSearch, '%') " + + "OR wb.id in (SELECT wbw.widgets_bundle_id FROM widgets_bundle_widget wbw, widget_type wtd " + + "WHERE wtd.id = wbw.widget_type_id " + + "AND (wtd.name ILIKE CONCAT('%', :textSearch, '%') " + + "OR wtd.description ILIKE CONCAT('%', :textSearch, '%') " + + "OR lower(wtd.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:textSearch), ' '))))", + countQuery = "SELECT count(*) FROM widgets_bundle wb WHERE wb.tenant_id = :systemTenantId " + + "AND (wb.title ILIKE CONCAT('%', :textSearch, '%') " + + "OR wb.description ILIKE CONCAT('%', :textSearch, '%') " + + "OR wb.id in (SELECT wbw.widgets_bundle_id FROM widgets_bundle_widget wbw, widget_type wtd " + + "WHERE wtd.id = wbw.widget_type_id " + + "AND (wtd.name ILIKE CONCAT('%', :textSearch, '%') " + + "OR wtd.description ILIKE CONCAT('%', :textSearch, '%') " + + "OR lower(wtd.tags\\:\\:text)\\:\\:text[] && string_to_array(lower(:textSearch), ' '))))" + ) + Page findSystemWidgetsBundlesFullSearch(@Param("systemTenantId") UUID systemTenantId, + @Param("textSearch") String textSearch, + Pageable pageable); + @Query("SELECT wb FROM WidgetsBundleEntity wb WHERE wb.tenantId = :tenantId " + "AND LOWER(wb.title) LIKE LOWER(CONCAT('%', :textSearch, '%'))") Page findTenantWidgetsBundlesByTenantId(@Param("tenantId") UUID tenantId, @@ -51,6 +73,29 @@ public interface WidgetsBundleRepository extends JpaRepository findAllTenantWidgetsBundlesByTenantIdFullSearch(@Param("tenantId") UUID tenantId, + @Param("nullTenantId") UUID nullTenantId, + @Param("textSearch") String textSearch, + Pageable pageable); + WidgetsBundleEntity findFirstByTenantIdAndTitle(UUID tenantId, String title); @Query("SELECT externalId FROM WidgetsBundleEntity WHERE id = :id") diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayType.java new file mode 100644 index 0000000000..a194b76aa5 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayType.java @@ -0,0 +1,45 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import org.hibernate.type.AbstractSingleColumnStandardBasicType; +import org.hibernate.usertype.DynamicParameterizedType; + +import java.util.Properties; + +public abstract class AbstractArrayType + extends AbstractSingleColumnStandardBasicType + implements DynamicParameterizedType { + + public static final String SQL_ARRAY_TYPE = "sql_array_type"; + + public AbstractArrayType(AbstractArrayTypeDescriptor arrayTypeDescriptor) { + super( + ArraySqlTypeDescriptor.INSTANCE, + arrayTypeDescriptor + ); + } + + @Override + protected boolean registerUnderJavaType() { + return true; + } + + @Override + public void setParameterValues(Properties parameters) { + ((AbstractArrayTypeDescriptor) getJavaTypeDescriptor()).setParameterValues(parameters); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java new file mode 100644 index 0000000000..91e426567c --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java @@ -0,0 +1,119 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import org.hibernate.HibernateException; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; +import org.hibernate.type.descriptor.java.MutabilityPlan; +import org.hibernate.type.descriptor.java.MutableMutabilityPlan; +import org.hibernate.usertype.DynamicParameterizedType; + +import java.sql.Array; +import java.sql.SQLException; +import java.util.Arrays; +import java.util.Properties; + +import static org.thingsboard.server.dao.util.mapping.AbstractArrayType.SQL_ARRAY_TYPE; + +public abstract class AbstractArrayTypeDescriptor + extends AbstractTypeDescriptor implements DynamicParameterizedType { + + private Class arrayObjectClass; + + private String sqlArrayType; + + public AbstractArrayTypeDescriptor(Class arrayObjectClass) { + this(arrayObjectClass, (MutabilityPlan) new MutableMutabilityPlan() { + @Override + protected T deepCopyNotNull(Object value) { + return ArrayUtil.deepCopy(value); + } + }); + } + + protected AbstractArrayTypeDescriptor(Class arrayObjectClass, MutabilityPlan mutableMutabilityPlan) { + super(arrayObjectClass, mutableMutabilityPlan); + this.arrayObjectClass = arrayObjectClass; + } + + public Class getArrayObjectClass() { + return arrayObjectClass; + } + + public void setArrayObjectClass(Class arrayObjectClass) { + this.arrayObjectClass = arrayObjectClass; + } + + @Override + public void setParameterValues(Properties parameters) { + if (parameters.containsKey(PARAMETER_TYPE)) { + arrayObjectClass = ((ParameterType) parameters.get(PARAMETER_TYPE)).getReturnedClass(); + } + sqlArrayType = parameters.getProperty(SQL_ARRAY_TYPE); + } + + @Override + public boolean areEqual(T one, T another) { + if (one == another) { + return true; + } + if (one == null || another == null) { + return false; + } + return ArrayUtil.isEquals(one, another); + } + + @Override + public String toString(T value) { + return Arrays.deepToString(ArrayUtil.wrapArray(value)); + } + + @Override + public T fromString(String string) { + return ArrayUtil.fromString(string, arrayObjectClass); + } + + @Override + public String extractLoggableRepresentation(T value) { + return (value == null) ? "null" : toString(value); + } + + @SuppressWarnings({"unchecked"}) + @Override + public X unwrap(T value, Class type, WrapperOptions options) { + return (X) ArrayUtil.wrapArray(value); + } + + @Override + public T wrap(X value, WrapperOptions options) { + if (value instanceof Array) { + Array array = (Array) value; + try { + return ArrayUtil.unwrapArray((Object[]) array.getArray(), arrayObjectClass); + } catch (SQLException e) { + throw new HibernateException( + new IllegalArgumentException(e) + ); + } + } + return (T) value; + } + + protected String getSqlArrayType() { + return sqlArrayType; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java new file mode 100644 index 0000000000..4baa150445 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java @@ -0,0 +1,86 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +public class ArraySqlTypeDescriptor implements SqlTypeDescriptor { + + public static final ArraySqlTypeDescriptor INSTANCE = new ArraySqlTypeDescriptor(); + + @Override + public int getSqlType() { + return Types.ARRAY; + } + + @Override + public boolean canBeRemapped() { + return true; + } + + @Override + public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder(javaTypeDescriptor, this) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + AbstractArrayTypeDescriptor abstractArrayTypeDescriptor = (AbstractArrayTypeDescriptor) javaTypeDescriptor; + st.setArray(index, st.getConnection().createArrayOf( + abstractArrayTypeDescriptor.getSqlArrayType(), + abstractArrayTypeDescriptor.unwrap(value, Object[].class, options) + )); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + throw new UnsupportedOperationException("Binding by name is not supported!"); + } + }; + } + + @Override + public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor(javaTypeDescriptor, this) { + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(rs.getArray(name), options); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(statement.getArray(index), options); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { + return javaTypeDescriptor.wrap(statement.getArray(name), options); + } + }; + } + +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java new file mode 100644 index 0000000000..eb940c1912 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java @@ -0,0 +1,335 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import java.lang.reflect.Array; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.List; + +public class ArrayUtil { + + public static T deepCopy(Object originalArray) { + Class arrayClass = originalArray.getClass(); + + if (boolean[].class.equals(arrayClass)) { + boolean[] array = (boolean[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (byte[].class.equals(arrayClass)) { + byte[] array = (byte[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (short[].class.equals(arrayClass)) { + short[] array = (short[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (int[].class.equals(arrayClass)) { + int[] array = (int[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (long[].class.equals(arrayClass)) { + long[] array = (long[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (float[].class.equals(arrayClass)) { + float[] array = (float[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (double[].class.equals(arrayClass)) { + double[] array = (double[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else if (char[].class.equals(arrayClass)) { + char[] array = (char[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } else { + Object[] array = (Object[]) originalArray; + return (T) Arrays.copyOf(array, array.length); + } + } + + public static Object[] wrapArray(Object originalArray) { + Class arrayClass = originalArray.getClass(); + + if (boolean[].class.equals(arrayClass)) { + boolean[] fromArray = (boolean[]) originalArray; + Boolean[] array = new Boolean[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (byte[].class.equals(arrayClass)) { + byte[] fromArray = (byte[]) originalArray; + Byte[] array = new Byte[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (short[].class.equals(arrayClass)) { + short[] fromArray = (short[]) originalArray; + Short[] array = new Short[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (int[].class.equals(arrayClass)) { + int[] fromArray = (int[]) originalArray; + Integer[] array = new Integer[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (long[].class.equals(arrayClass)) { + long[] fromArray = (long[]) originalArray; + Long[] array = new Long[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (float[].class.equals(arrayClass)) { + float[] fromArray = (float[]) originalArray; + Float[] array = new Float[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (double[].class.equals(arrayClass)) { + double[] fromArray = (double[]) originalArray; + Double[] array = new Double[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (char[].class.equals(arrayClass)) { + char[] fromArray = (char[]) originalArray; + Character[] array = new Character[fromArray.length]; + for (int i = 0; i < fromArray.length; i++) { + array[i] = fromArray[i]; + } + return array; + } else if (originalArray instanceof Collection) { + return ((Collection) originalArray).toArray(); + } else { + return (Object[]) originalArray; + } + } + + public static T unwrapArray(Object[] originalArray, Class arrayClass) { + + if (boolean[].class.equals(arrayClass)) { + boolean[] array = new boolean[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Boolean) originalArray[i] : Boolean.FALSE; + } + return (T) array; + } else if (byte[].class.equals(arrayClass)) { + byte[] array = new byte[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Byte) originalArray[i] : 0; + } + return (T) array; + } else if (short[].class.equals(arrayClass)) { + short[] array = new short[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Short) originalArray[i] : 0; + } + return (T) array; + } else if (int[].class.equals(arrayClass)) { + int[] array = new int[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Integer) originalArray[i] : 0; + } + return (T) array; + } else if (long[].class.equals(arrayClass)) { + long[] array = new long[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Long) originalArray[i] : 0L; + } + return (T) array; + } else if (float[].class.equals(arrayClass)) { + float[] array = new float[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? ((Number) originalArray[i]).floatValue() : 0f; + } + return (T) array; + } else if (double[].class.equals(arrayClass)) { + double[] array = new double[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Double) originalArray[i] : 0d; + } + return (T) array; + } else if (char[].class.equals(arrayClass)) { + char[] array = new char[originalArray.length]; + for (int i = 0; i < originalArray.length; i++) { + array[i] = originalArray[i] != null ? (Character) originalArray[i] : 0; + } + return (T) array; + } else if (Enum[].class.isAssignableFrom(arrayClass)) { + T array = arrayClass.cast(Array.newInstance(arrayClass.getComponentType(), originalArray.length)); + for (int i = 0; i < originalArray.length; i++) { + Object objectValue = originalArray[i]; + if (objectValue != null) { + String stringValue = (objectValue instanceof String) ? (String) objectValue : String.valueOf(objectValue); + objectValue = Enum.valueOf((Class) arrayClass.getComponentType(), stringValue); + } + Array.set(array, i, objectValue); + } + return array; + } else if (java.time.LocalDate[].class.equals(arrayClass) && java.sql.Date[].class.equals(originalArray.getClass())) { + // special case because conversion is neither with ctor nor valueOf + Object[] array = (Object[]) Array.newInstance(java.time.LocalDate.class, originalArray.length); + for (int i = 0; i < array.length; ++i) { + array[i] = originalArray[i] != null ? ((java.sql.Date) originalArray[i]).toLocalDate() : null; + } + return (T) array; + } else if (java.time.LocalDateTime[].class.equals(arrayClass) && java.sql.Timestamp[].class.equals(originalArray.getClass())) { + // special case because conversion is neither with ctor nor valueOf + Object[] array = (Object[]) Array.newInstance(java.time.LocalDateTime.class, originalArray.length); + for (int i = 0; i < array.length; ++i) { + array[i] = originalArray[i] != null ? ((java.sql.Timestamp) originalArray[i]).toLocalDateTime() : null; + } + return (T) array; + } else if(arrayClass.getComponentType() != null && arrayClass.getComponentType().isArray()) { + int arrayLength = originalArray.length; + Object[] array = (Object[]) Array.newInstance(arrayClass.getComponentType(), arrayLength); + if (arrayLength > 0) { + for (int i = 0; i < originalArray.length; i++) { + array[i] = unwrapArray((Object[]) originalArray[i], arrayClass.getComponentType()); + } + } + return (T) array; + } else { + if (arrayClass.isInstance(originalArray)) { + return (T) originalArray; + } else { + return (T) Arrays.copyOf(originalArray, originalArray.length, (Class) arrayClass); + } + } + } + + public static T fromString(String string, Class arrayClass) { + String stringArray = string.replaceAll("[\\[\\]]", ""); + String[] tokens = stringArray.split(","); + + int length = tokens.length; + + if (boolean[].class.equals(arrayClass)) { + boolean[] array = new boolean[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Boolean.valueOf(tokens[i]); + } + return (T) array; + } else if (byte[].class.equals(arrayClass)) { + byte[] array = new byte[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Byte.valueOf(tokens[i]); + } + return (T) array; + } else if (short[].class.equals(arrayClass)) { + short[] array = new short[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Short.valueOf(tokens[i]); + } + return (T) array; + } else if (int[].class.equals(arrayClass)) { + int[] array = new int[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Integer.valueOf(tokens[i]); + } + return (T) array; + } else if (long[].class.equals(arrayClass)) { + long[] array = new long[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Long.valueOf(tokens[i]); + } + return (T) array; + } else if (float[].class.equals(arrayClass)) { + float[] array = new float[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Float.valueOf(tokens[i]); + } + return (T) array; + } else if (double[].class.equals(arrayClass)) { + double[] array = new double[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = Double.valueOf(tokens[i]); + } + return (T) array; + } else if (char[].class.equals(arrayClass)) { + char[] array = new char[length]; + for (int i = 0; i < tokens.length; i++) { + array[i] = tokens[i].length() > 0 ? tokens[i].charAt(0) : Character.MIN_VALUE; + } + return (T) array; + } else { + return (T) tokens; + } + } + + public static boolean isEquals(Object firstArray, Object secondArray) { + if (firstArray.getClass() != secondArray.getClass()) { + return false; + } + Class arrayClass = firstArray.getClass(); + + if (boolean[].class.equals(arrayClass)) { + return Arrays.equals((boolean[]) firstArray, (boolean[]) secondArray); + } else if (byte[].class.equals(arrayClass)) { + return Arrays.equals((byte[]) firstArray, (byte[]) secondArray); + } else if (short[].class.equals(arrayClass)) { + return Arrays.equals((short[]) firstArray, (short[]) secondArray); + } else if (int[].class.equals(arrayClass)) { + return Arrays.equals((int[]) firstArray, (int[]) secondArray); + } else if (long[].class.equals(arrayClass)) { + return Arrays.equals((long[]) firstArray, (long[]) secondArray); + } else if (float[].class.equals(arrayClass)) { + return Arrays.equals((float[]) firstArray, (float[]) secondArray); + } else if (double[].class.equals(arrayClass)) { + return Arrays.equals((double[]) firstArray, (double[]) secondArray); + } else if (char[].class.equals(arrayClass)) { + return Arrays.equals((char[]) firstArray, (char[]) secondArray); + } else { + return Arrays.equals((Object[]) firstArray, (Object[]) secondArray); + } + } + + public static Class toArrayClass(Class arrayElementClass) { + + if (boolean.class.equals(arrayElementClass)) { + return (Class) boolean[].class; + } else if (byte.class.equals(arrayElementClass)) { + return (Class) byte[].class; + } else if (short.class.equals(arrayElementClass)) { + return (Class) short[].class; + } else if (int.class.equals(arrayElementClass)) { + return (Class) int[].class; + } else if (long.class.equals(arrayElementClass)) { + return (Class) long[].class; + } else if (float.class.equals(arrayElementClass)) { + return (Class) float[].class; + } else if (double[].class.equals(arrayElementClass)) { + return (Class) double[].class; + } else if (char[].class.equals(arrayElementClass)) { + return (Class) char[].class; + } else { + Object array = Array.newInstance(arrayElementClass, 0); + return (Class) array.getClass(); + } + } + + public static List asList(T[] array) { + List list = new ArrayList(array.length); + for (int i = 0; i < array.length; i++) { + list.add(i, array[i]); + } + return list; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java new file mode 100644 index 0000000000..53faf75720 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java @@ -0,0 +1,64 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import org.hibernate.usertype.DynamicParameterizedType; + +import java.lang.annotation.Annotation; + +public class ParameterizedParameterType implements DynamicParameterizedType.ParameterType { + + private final Class clasz; + + public ParameterizedParameterType(Class clasz) { + this.clasz = clasz; + } + + @Override + public Class getReturnedClass() { + return clasz; + } + + @Override + public Annotation[] getAnnotationsMethod() { + return new Annotation[0]; + } + + @Override + public String getCatalog() { + throw new UnsupportedOperationException(); + } + + @Override + public String getSchema() { + throw new UnsupportedOperationException(); + } + + @Override + public String getTable() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isPrimaryKey() { + throw new UnsupportedOperationException(); + } + + @Override + public String[] getColumns() { + throw new UnsupportedOperationException(); + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java new file mode 100644 index 0000000000..cd2ee52a35 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java @@ -0,0 +1,41 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +import org.hibernate.usertype.DynamicParameterizedType; +import java.util.Properties; + +public class StringArrayType extends AbstractArrayType { + + public static final StringArrayType INSTANCE = new StringArrayType(); + + public StringArrayType() { + super( + new StringArrayTypeDescriptor() + ); + } + + public StringArrayType(Class arrayClass) { + this(); + Properties parameters = new Properties(); + parameters.put(DynamicParameterizedType.PARAMETER_TYPE, new ParameterizedParameterType(arrayClass)); + setParameterValues(parameters); + } + + public String getName() { + return "string-array"; + } +} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java new file mode 100644 index 0000000000..8846d0a5e2 --- /dev/null +++ b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java @@ -0,0 +1,31 @@ +/** + * Copyright © 2016-2023 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.util.mapping; + +public class StringArrayTypeDescriptor + extends AbstractArrayTypeDescriptor { + + public StringArrayTypeDescriptor() { + super(String[].class); + } + + @Override + protected String getSqlArrayType() { + String sqlArrayType = super.getSqlArrayType(); + return sqlArrayType != null ? sqlArrayType : "text"; + } +} + diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java index d9d19a9617..96d93a34f1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetTypeDao.java @@ -19,6 +19,7 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; @@ -53,11 +54,11 @@ public interface WidgetTypeDao extends Dao, ExportableEntityD boolean existsByTenantIdAndId(TenantId tenantId, UUID widgetTypeId); - PageData findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, PageLink pageLink); + PageData findSystemWidgetTypes(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); - PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink); + PageData findAllTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); - PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink); + PageData findTenantWidgetTypesByTenantId(UUID tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); /** * Find widget types by widgetsBundleId. @@ -77,14 +78,7 @@ public interface WidgetTypeDao extends Dao, ExportableEntityD */ List findWidgetTypesDetailsByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId); - /** - * Find widget types infos by widgetsBundleId. - * - * @param tenantId the tenantId - * @param widgetsBundleId the widgets bundle id - * @return the list of widget types infos objects - */ - List findWidgetTypesInfosByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId); + PageData findWidgetTypesInfosByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink); List findWidgetFqnsByWidgetsBundleId(UUID tenantId, UUID widgetsBundleId); 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 4bd0b62f4b..2e347f2b62 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 @@ -27,6 +27,7 @@ import org.thingsboard.server.common.data.id.WidgetTypeId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; import org.thingsboard.server.common.data.widget.WidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; @@ -110,26 +111,28 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { } @Override - public PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) { - log.trace("Executing findSystemWidgetTypesByPageLink, fullSearch [{}] pageLink [{}]", fullSearch, pageLink); + public PageData findSystemWidgetTypesByPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + log.trace("Executing findSystemWidgetTypesByPageLink, fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", fullSearch, deprecatedFilter, widgetTypes, pageLink); Validator.validatePageLink(pageLink); - return widgetTypeDao.findSystemWidgetTypes(tenantId, fullSearch, pageLink); + return widgetTypeDao.findSystemWidgetTypes(tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); } @Override - public PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) { - log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], pageLink [{}]", tenantId, fullSearch, pageLink); + public PageData findAllTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + log.trace("Executing findAllTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", + tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validatePageLink(pageLink); - return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, pageLink); + return widgetTypeDao.findAllTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); } @Override - public PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) { - log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], pageLink [{}]", tenantId, fullSearch, pageLink); + public PageData findTenantWidgetTypesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + log.trace("Executing findTenantWidgetTypesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", + tenantId, fullSearch, deprecatedFilter, widgetTypes, pageLink); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validatePageLink(pageLink); - return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, pageLink); + return widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); } @Override @@ -150,11 +153,14 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { } @Override - public List findWidgetTypesInfosByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId) { - log.trace("Executing findWidgetTypesInfosByWidgetsBundleId, tenantId [{}], widgetsBundleId [{}]", tenantId, widgetsBundleId); + public PageData findWidgetTypesInfosByWidgetsBundleId(TenantId tenantId, WidgetsBundleId widgetsBundleId, boolean fullSearch, + DeprecatedFilter deprecatedFilter, List widgetTypes, PageLink pageLink) { + log.trace("Executing findWidgetTypesInfosByWidgetsBundleId, tenantId [{}], widgetsBundleId [{}], fullSearch [{}], deprecatedFilter [{}], widgetTypes [{}], pageLink [{}]", + tenantId, widgetsBundleId, fullSearch, deprecatedFilter, widgetTypes, pageLink); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validateId(widgetsBundleId, INCORRECT_WIDGETS_BUNDLE_ID + widgetsBundleId); - return widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(tenantId.getId(), widgetsBundleId.getId()); + Validator.validatePageLink(pageLink); + return widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(tenantId.getId(), widgetsBundleId.getId(), fullSearch, deprecatedFilter, widgetTypes, pageLink); } @Override @@ -230,7 +236,7 @@ public class WidgetTypeServiceImpl implements WidgetTypeService { @Override protected PageData findEntities(TenantId tenantId, TenantId id, PageLink pageLink) { - return widgetTypeDao.findTenantWidgetTypesByTenantId(id.getId(), false, pageLink); + return widgetTypeDao.findTenantWidgetTypesByTenantId(id.getId(), false, DeprecatedFilter.ALL, null, pageLink); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java index e4b1762426..b5486b61b1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/widget/WidgetsBundleDao.java @@ -54,7 +54,7 @@ public interface WidgetsBundleDao extends Dao, ExportableEntityDa * @param pageLink the page link * @return the list of widgets bundles objects */ - PageData findSystemWidgetsBundles(TenantId tenantId, PageLink pageLink); + PageData findSystemWidgetsBundles(TenantId tenantId, boolean fullSearch, PageLink pageLink); /** * Find tenant widgets bundles by tenantId and page link. @@ -72,7 +72,7 @@ public interface WidgetsBundleDao extends Dao, ExportableEntityDa * @param pageLink the page link * @return the list of widgets bundles objects */ - PageData findAllTenantWidgetsBundlesByTenantId(UUID tenantId, PageLink pageLink); + PageData findAllTenantWidgetsBundlesByTenantId(UUID tenantId, boolean fullSearch, PageLink pageLink); } 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 4f094ca62f..998cbb6e31 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 @@ -104,10 +104,10 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { } @Override - public PageData findSystemWidgetsBundlesByPageLink(TenantId tenantId, PageLink pageLink) { - log.trace("Executing findSystemWidgetsBundles, pageLink [{}]", pageLink); + public PageData findSystemWidgetsBundlesByPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) { + log.trace("Executing findSystemWidgetsBundles, fullSearch [{}], pageLink [{}]", fullSearch, pageLink); Validator.validatePageLink(pageLink); - return widgetsBundleDao.findSystemWidgetsBundles(tenantId, pageLink); + return widgetsBundleDao.findSystemWidgetsBundles(tenantId, fullSearch, pageLink); } @Override @@ -117,7 +117,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { PageLink pageLink = new PageLink(DEFAULT_WIDGETS_BUNDLE_LIMIT); PageData pageData; do { - pageData = findSystemWidgetsBundlesByPageLink(tenantId, pageLink); + pageData = findSystemWidgetsBundlesByPageLink(tenantId, false, pageLink); widgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -135,11 +135,11 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { } @Override - public PageData findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, PageLink pageLink) { - log.trace("Executing findAllTenantWidgetsBundlesByTenantIdAndPageLink, tenantId [{}], pageLink [{}]", tenantId, pageLink); + public PageData findAllTenantWidgetsBundlesByTenantIdAndPageLink(TenantId tenantId, boolean fullSearch, PageLink pageLink) { + log.trace("Executing findAllTenantWidgetsBundlesByTenantIdAndPageLink, tenantId [{}], fullSearch [{}], pageLink [{}]", tenantId, fullSearch, pageLink); Validator.validateId(tenantId, INCORRECT_TENANT_ID + tenantId); Validator.validatePageLink(pageLink); - return widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId.getId(), pageLink); + return widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId.getId(), fullSearch, pageLink); } @Override @@ -150,7 +150,7 @@ public class WidgetsBundleServiceImpl implements WidgetsBundleService { PageLink pageLink = new PageLink(DEFAULT_WIDGETS_BUNDLE_LIMIT); PageData pageData; do { - pageData = findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink); + pageData = findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, false, pageLink); widgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4df73de9d6..b1ae32704e 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -489,6 +489,7 @@ CREATE TABLE IF NOT EXISTS widget_type ( image varchar(1000000), deprecated boolean NOT NULL DEFAULT false, description varchar(1024), + tags text[], external_id uuid, CONSTRAINT uq_widget_type_fqn UNIQUE (tenant_id, fqn), CONSTRAINT widget_type_external_id_unq_key UNIQUE (tenant_id, external_id) diff --git a/dao/src/main/resources/sql/schema-views-and-functions.sql b/dao/src/main/resources/sql/schema-views-and-functions.sql index 3aa797d7b6..1aa5647bde 100644 --- a/dao/src/main/resources/sql/schema-views-and-functions.sql +++ b/dao/src/main/resources/sql/schema-views-and-functions.sql @@ -285,3 +285,9 @@ BEGIN RETURN json_build_object('success', true, 'modified', modified, 'alarm', row_to_json(result))::text; END $$; + +DROP VIEW IF EXISTS widget_type_info_view CASCADE; +CREATE OR REPLACE VIEW widget_type_info_view AS +SELECT t.* + , COALESCE((t.descriptor::json->>'type')::text, '') as widget_type +FROM widget_type t; diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/WidgetsBundleServiceTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/WidgetsBundleServiceTest.java index 0f5c90b4a8..da594bb9c7 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/service/WidgetsBundleServiceTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/service/WidgetsBundleServiceTest.java @@ -174,7 +174,7 @@ public class WidgetsBundleServiceTest extends AbstractServiceTest { PageLink pageLink = new PageLink(19); PageData pageData = null; do { - pageData = widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, pageLink); + pageData = widgetsBundleService.findSystemWidgetsBundlesByPageLink(tenantId, false, pageLink); loadedWidgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -297,7 +297,7 @@ public class WidgetsBundleServiceTest extends AbstractServiceTest { PageLink pageLink = new PageLink(17); PageData pageData = null; do { - pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink); + pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, false, pageLink); loadedWidgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -314,7 +314,7 @@ public class WidgetsBundleServiceTest extends AbstractServiceTest { loadedWidgetsBundles.clear(); pageLink = new PageLink(14); do { - pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink); + pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, false, pageLink); loadedWidgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); @@ -336,7 +336,7 @@ public class WidgetsBundleServiceTest extends AbstractServiceTest { loadedWidgetsBundles.clear(); pageLink = new PageLink(18); do { - pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, pageLink); + pageData = widgetsBundleService.findAllTenantWidgetsBundlesByTenantIdAndPageLink(tenantId, false, pageLink); loadedWidgetsBundles.addAll(pageData.getData()); if (pageData.hasNext()) { pageLink = pageLink.nextPageLink(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java index 8d289c6e1a..420887c844 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDaoTest.java @@ -20,10 +20,17 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; +import org.thingsboard.server.common.data.page.PageData; +import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; +import org.thingsboard.server.common.data.widget.BaseWidgetType; +import org.thingsboard.server.common.data.widget.DeprecatedFilter; 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 org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.dao.AbstractJpaDaoTest; @@ -31,7 +38,10 @@ import org.thingsboard.server.dao.widget.WidgetTypeDao; import org.thingsboard.server.dao.widget.WidgetsBundleDao; import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; import java.util.List; +import java.util.UUID; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @@ -43,7 +53,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { final String BUNDLE_ALIAS = "BUNDLE_ALIAS"; final int WIDGET_TYPE_COUNT = 3; - List widgetTypeList; + List widgetTypeList; WidgetsBundle widgetsBundle; @Autowired @@ -64,17 +74,24 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { this.widgetsBundle = widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle); for (int i = 0; i < WIDGET_TYPE_COUNT; i++) { - var widgetType = createAndSaveWidgetType(i); + var widgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, i); widgetTypeList.add(widgetType); widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(this.widgetsBundle.getId(), widgetType.getId(), i)); } + widgetTypeList.sort(Comparator.comparing(BaseWidgetType::getName)); } - WidgetType createAndSaveWidgetType(int number) { + WidgetTypeDetails createAndSaveWidgetType(TenantId tenantId, int number) { WidgetTypeDetails widgetType = new WidgetTypeDetails(); - widgetType.setTenantId(TenantId.SYS_TENANT_ID); + widgetType.setTenantId(tenantId); widgetType.setName("WIDGET_TYPE_" + number); + widgetType.setDescription("WIDGET_TYPE_DESCRIPTION" + number); widgetType.setFqn("FQN_" + number); + var descriptor = JacksonUtil.newObjectNode(); + descriptor.put("type", number % 2 == 0 ? "latest" : "static"); + widgetType.setDescriptor(descriptor); + String[] tags = new String[]{"Tag1_"+number, "Tag2_"+number, "TEST_"+number}; + widgetType.setTags(tags); return widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType); } @@ -92,6 +109,48 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { assertEquals(WIDGET_TYPE_COUNT, widgetTypes.size()); } + @Test + public void testFindSystemWidgetTypes() { + PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), + new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("name"))); + assertEquals(1, widgetTypes.getData().size()); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(1)), widgetTypes.getData().get(0)); + + widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.emptyList(), + new PageLink(1024, 0, "hfgfd tag2_2 ghg", new SortOrder("name"))); + assertEquals(1, widgetTypes.getData().size()); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(0)); + } + + @Test + public void testFindTenantWidgetTypesByTenantId() { + UUID tenantId = Uuids.timeBased(); + for (int i = 0; i < WIDGET_TYPE_COUNT; i++) { + var widgetType = createAndSaveWidgetType(new TenantId(tenantId), i); + widgetTypeList.add(widgetType); + } + PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId, true, DeprecatedFilter.ALL, null, + new PageLink(10, 0, "", new SortOrder("name"))); + assertEquals(WIDGET_TYPE_COUNT, widgetTypes.getData().size()); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(3)), widgetTypes.getData().get(0)); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(4)), widgetTypes.getData().get(1)); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(5)), widgetTypes.getData().get(2)); + } + + @Test + public void testFindByWidgetTypeInfosByBundleId() { + PageData widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(),true, DeprecatedFilter.ALL, Collections.singletonList("latest"), + new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("name"))); + assertEquals(2, widgetTypes.getData().size()); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0)); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(1)); + + widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(), true, DeprecatedFilter.ALL, Collections.emptyList(), + new PageLink(1024, 0, "hfgfd TEST_0 ghg", new SortOrder("name"))); + assertEquals(1, widgetTypes.getData().size()); + assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0)); + } + @Test public void testFindByTenantIdAndFqn() { WidgetType result = widgetTypeList.get(0); 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 e1758c4660..424bda88f7 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 @@ -17,18 +17,27 @@ package org.thingsboard.server.dao.sql.widget; import com.datastax.oss.driver.api.core.uuid.Uuids; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.page.SortOrder; +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 org.thingsboard.server.common.data.widget.WidgetsBundleWidget; import org.thingsboard.server.dao.AbstractJpaDaoTest; +import org.thingsboard.server.dao.widget.WidgetTypeDao; import org.thingsboard.server.dao.widget.WidgetsBundleDao; +import java.util.ArrayList; +import java.util.Comparator; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import static org.junit.Assert.assertEquals; @@ -38,15 +47,27 @@ import static org.junit.Assert.assertEquals; public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { List widgetsBundles; + List widgetTypeList; + @Autowired private WidgetsBundleDao widgetsBundleDao; + @Autowired + private WidgetTypeDao widgetTypeDao; + + @Before + public void setUp() { + widgetTypeList = new ArrayList<>(); + } + @After public void tearDown() { for (WidgetsBundle widgetsBundle : widgetsBundles) { widgetsBundleDao.removeById(widgetsBundle.getTenantId(), widgetsBundle.getUuidId()); } - + for (WidgetType widgetType : widgetTypeList) { + widgetTypeDao.removeById(TenantId.SYS_TENANT_ID, widgetType.getUuidId()); + } } @Test @@ -72,14 +93,53 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { assertEquals(30, widgetsBundles.size()); // Get first page PageLink pageLink = new PageLink(10, 0, "WB"); - PageData widgetsBundles1 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, pageLink); + PageData widgetsBundles1 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, false, pageLink); assertEquals(10, widgetsBundles1.getData().size()); // Get next page pageLink = pageLink.nextPageLink(); - PageData widgetsBundles2 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, pageLink); + PageData widgetsBundles2 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, false, pageLink); assertEquals(10, widgetsBundles2.getData().size()); } + @Test + public void testFindSystemWidgetsBundlesFullSearch() { + createSystemWidgetBundles(30, "WB_"); + widgetsBundles = widgetsBundleDao.find(TenantId.SYS_TENANT_ID).stream().sorted(Comparator.comparing(WidgetsBundle::getTitle)).collect(Collectors.toList()); + assertEquals(30, widgetsBundles.size()); + + var widgetType1 = createAndSaveWidgetType(TenantId.SYS_TENANT_ID,1, "Test widget type 1", "This is the widget type 1", new String[]{"tag1", "Tag2", "TEST_TAG"}); + var widgetType2 = createAndSaveWidgetType(TenantId.SYS_TENANT_ID,2, "Test widget type 2", "This is the widget type 2", new String[]{"tag3", "Tag5", "TEST_Tag2"}); + + var widgetsBundle1 = widgetsBundles.get(10); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle1.getId(), widgetType1.getId(), 0)); + + var widgetsBundle2 = widgetsBundles.get(15); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle2.getId(), widgetType2.getId(), 0)); + + + var widgetsBundle3 = widgetsBundles.get(28); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle3.getId(), widgetType1.getId(), 0)); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle3.getId(), widgetType2.getId(), 1)); + + PageLink pageLink = new PageLink(10, 0, "widget type 1", new SortOrder("title")); + PageData widgetsBundles1 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, true, pageLink); + assertEquals(2, widgetsBundles1.getData().size()); + assertEquals(widgetsBundle1, widgetsBundles1.getData().get(0)); + assertEquals(widgetsBundle3, widgetsBundles1.getData().get(1)); + + pageLink = new PageLink(10, 0, "Test widget type 2", new SortOrder("title")); + PageData widgetsBundles2 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, true, pageLink); + assertEquals(2, widgetsBundles2.getData().size()); + assertEquals(widgetsBundle2, widgetsBundles2.getData().get(0)); + assertEquals(widgetsBundle3, widgetsBundles2.getData().get(1)); + + pageLink = new PageLink(10, 0, "ppp Fd v TAG1 tt", new SortOrder("title")); + PageData widgetsBundles3 = widgetsBundleDao.findSystemWidgetsBundles(TenantId.SYS_TENANT_ID, true, pageLink); + assertEquals(2, widgetsBundles3.getData().size()); + assertEquals(widgetsBundle1, widgetsBundles3.getData().get(0)); + assertEquals(widgetsBundle3, widgetsBundles3.getData().get(1)); + } + @Test public void testFindWidgetsBundlesByTenantId() { UUID tenantId1 = Uuids.timeBased(); @@ -120,22 +180,71 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { assertEquals(100, widgetsBundleDao.find(TenantId.SYS_TENANT_ID).size()); PageLink pageLink = new PageLink(30, 0, "WB"); - PageData widgetsBundles1 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, pageLink); + PageData widgetsBundles1 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, false, pageLink); assertEquals(30, widgetsBundles1.getData().size()); pageLink = pageLink.nextPageLink(); - PageData widgetsBundles2 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, pageLink); + PageData widgetsBundles2 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, false, pageLink); assertEquals(30, widgetsBundles2.getData().size()); pageLink = pageLink.nextPageLink(); - PageData widgetsBundles3 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, pageLink); + PageData widgetsBundles3 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, false, pageLink); assertEquals(10, widgetsBundles3.getData().size()); pageLink = pageLink.nextPageLink(); - PageData widgetsBundles4 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, pageLink); + PageData widgetsBundles4 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, false, pageLink); assertEquals(0, widgetsBundles4.getData().size()); } + @Test + public void testFindAllWidgetsBundlesByTenantIdFullSearch() { + UUID tenantId1 = Uuids.timeBased(); + UUID tenantId2 = Uuids.timeBased(); + for (int i = 0; i < 10; i++) { + createWidgetBundles(5, tenantId1, "WB1_" + i + "_"); + createWidgetBundles(3, tenantId2, "WB2_" + i + "_"); + createSystemWidgetBundles(2, "WB_SYS_" + i + "_"); + } + widgetsBundles = widgetsBundleDao.find(TenantId.SYS_TENANT_ID).stream().sorted(Comparator.comparing(WidgetsBundle::getTitle)).collect(Collectors.toList());; + assertEquals(100, widgetsBundleDao.find(TenantId.SYS_TENANT_ID).size()); + + var widgetType1 = createAndSaveWidgetType(new TenantId(tenantId1), 1, "Test widget type 1", "This is the widget type 1", new String[]{"tag1", "Tag2", "TEST_TAG"}); + var widgetType2 = createAndSaveWidgetType(new TenantId(tenantId2), 2, "Test widget type 2", "This is the widget type 2", new String[]{"tag3", "Tag5", "TEST_Tag2"}); + + var widgetsBundle1 = widgetsBundles.stream().filter(widgetsBundle -> widgetsBundle.getTenantId().getId().equals(tenantId1)).collect(Collectors.toList()).get(10); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle1.getId(), widgetType1.getId(), 0)); + + var widgetsBundle2 = widgetsBundles.stream().filter(widgetsBundle -> widgetsBundle.getTenantId().getId().equals(tenantId2)).collect(Collectors.toList()).get(15); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle2.getId(), widgetType2.getId(), 0)); + + var widgetsBundle3 = widgetsBundles.stream().filter(widgetsBundle -> widgetsBundle.getTenantId().getId().equals(tenantId2)).collect(Collectors.toList()).get(28); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle3.getId(), widgetType1.getId(), 0)); + widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(widgetsBundle3.getId(), widgetType2.getId(), 1)); + + PageLink pageLink = new PageLink(10, 0, "widget type 1", new SortOrder("title")); + PageData widgetsBundles1 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, true, pageLink); + assertEquals(1, widgetsBundles1.getData().size()); + assertEquals(widgetsBundle1, widgetsBundles1.getData().get(0)); + + pageLink = new PageLink(10, 0, "Test widget type 2", new SortOrder("title")); + PageData widgetsBundles2 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, true, pageLink); + assertEquals(0, widgetsBundles2.getData().size()); + + PageData widgetsBundles3 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId2, true, pageLink); + assertEquals(2, widgetsBundles3.getData().size()); + assertEquals(widgetsBundle2, widgetsBundles3.getData().get(0)); + assertEquals(widgetsBundle3, widgetsBundles3.getData().get(1)); + + pageLink = new PageLink(10, 0, "ttt Tag2 ffff hhhh", new SortOrder("title")); + PageData widgetsBundles4 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId1, true, pageLink); + assertEquals(1, widgetsBundles4.getData().size()); + assertEquals(widgetsBundle1, widgetsBundles4.getData().get(0)); + + PageData widgetsBundles5 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId2, true, pageLink); + assertEquals(1, widgetsBundles5.getData().size()); + assertEquals(widgetsBundle3, widgetsBundles5.getData().get(0)); + } + @Test public void testSearchTextNotFound() { UUID tenantId = Uuids.timeBased(); @@ -144,7 +253,7 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { widgetsBundles = widgetsBundleDao.find(TenantId.SYS_TENANT_ID); assertEquals(10, widgetsBundleDao.find(TenantId.SYS_TENANT_ID).size()); PageLink textPageLink = new PageLink(30, 0, "TEXT_NOT_FOUND"); - PageData widgetsBundles4 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId, textPageLink); + PageData widgetsBundles4 = widgetsBundleDao.findAllTenantWidgetsBundlesByTenantId(tenantId, false, textPageLink); assertEquals(0, widgetsBundles4.getData().size()); } @@ -169,4 +278,16 @@ public class JpaWidgetsBundleDaoTest extends AbstractJpaDaoTest { widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle); } } + + WidgetType createAndSaveWidgetType(TenantId tenantId, int number, String name, String description, String[] tags) { + WidgetTypeDetails widgetType = new WidgetTypeDetails(); + widgetType.setTenantId(tenantId); + widgetType.setName(name); + widgetType.setDescription(description); + widgetType.setTags(tags); + widgetType.setFqn("FQN_" + number); + var saved = widgetTypeDao.save(TenantId.SYS_TENANT_ID, widgetType); + this.widgetTypeList.add(saved); + return saved; + } } diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 12f6300b93..69ca114001 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -416,7 +416,7 @@ export class EntityService { break; case EntityType.WIDGETS_BUNDLE: pageLink.sortOrder.property = 'title'; - entitiesObservable = this.widgetService.getWidgetBundles(pageLink, config); + entitiesObservable = this.widgetService.getWidgetBundles(pageLink, false, config); break; case EntityType.NOTIFICATION_TARGET: pageLink.sortOrder.property = 'name'; diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 6affb01efe..9dcda4ef8a 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -23,6 +23,7 @@ import { PageData } from '@shared/models/page/page-data'; import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { BaseWidgetType, + DeprecatedFilter, fullWidgetTypeFqn, WidgetType, widgetType, @@ -46,8 +47,6 @@ export class WidgetService { private systemWidgetsBundles: Array; private tenantWidgetsBundles: Array; - private widgetTypeInfosCache = new Map>(); - private widgetsInfoInMemoryCache = new Map(); private loadWidgetsBundleCacheSubject: ReplaySubject; @@ -86,8 +85,8 @@ export class WidgetService { ); } - public getWidgetBundles(pageLink: PageLink, config?: RequestConfig): Observable> { - return this.http.get>(`/api/widgetsBundles${pageLink.toQuery()}`, + public getWidgetBundles(pageLink: PageLink, fullSearch = false, config?: RequestConfig): Observable> { + return this.http.get>(`/api/widgetsBundles${pageLink.toQuery()}&fullSearch=${fullSearch}`, defaultHttpOptionsFromConfig(config)); } @@ -109,21 +108,13 @@ export class WidgetService { public updateWidgetsBundleWidgetTypes(widgetsBundleId: string, widgetTypeIds: Array, config?: RequestConfig): Observable { return this.http.post(`/api/widgetsBundle/${widgetsBundleId}/widgetTypes`, widgetTypeIds, - defaultHttpOptionsFromConfig(config)).pipe( - tap(() => { - this.widgetTypeInfosCache.delete(widgetsBundleId); - }) - ); + defaultHttpOptionsFromConfig(config)); } public updateWidgetsBundleWidgetFqns(widgetsBundleId: string, widgetTypeFqns: Array, config?: RequestConfig): Observable { return this.http.post(`/api/widgetsBundle/${widgetsBundleId}/widgetTypeFqns`, widgetTypeFqns, - defaultHttpOptionsFromConfig(config)).pipe( - tap(() => { - this.widgetTypeInfosCache.delete(widgetsBundleId); - }) - ); + defaultHttpOptionsFromConfig(config)); } public deleteWidgetsBundle(widgetsBundleId: string, config?: RequestConfig) { @@ -155,16 +146,27 @@ export class WidgetService { defaultHttpOptionsFromConfig(config)); } - public getBundleWidgetTypeInfos(widgetsBundleId: string, - config?: RequestConfig): Observable> { - if (this.widgetTypeInfosCache.has(widgetsBundleId)) { - return of(this.widgetTypeInfosCache.get(widgetsBundleId)); - } else { - return this.http.get>(`/api/widgetTypesInfos?widgetsBundleId=${widgetsBundleId}`, - defaultHttpOptionsFromConfig(config)).pipe( - tap((res) => this.widgetTypeInfosCache.set(widgetsBundleId, res) ) - ); + public getBundleWidgetTypeInfosList(widgetsBundleId: string, + config?: RequestConfig): Observable> { + return this.getBundleWidgetTypeInfos(new PageLink(1024), widgetsBundleId, false, DeprecatedFilter.ALL, null, config).pipe( + map((data) => data.data) + ); + } + + public getBundleWidgetTypeInfos(pageLink: PageLink, + widgetsBundleId: string, + fullSearch = false, + deprecatedFilter = DeprecatedFilter.ALL, + widgetTypes: Array = null, + config?: RequestConfig): Observable> { + + let url = + `/api/widgetTypesInfos${pageLink.toQuery()}&widgetsBundleId=${widgetsBundleId}` + + `&fullSearch=${fullSearch}&deprecatedFilter=${deprecatedFilter}`; + if (widgetTypes && widgetTypes.length) { + url += `&widgetTypeList=${widgetTypes.join(',')}`; } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } public getWidgetType(fullFqn: string, config?: RequestConfig): Observable { @@ -224,10 +226,14 @@ export class WidgetService { } public getWidgetTypes(pageLink: PageLink, tenantOnly = false, - fullSearch = false, config?: RequestConfig): Observable> { - return this.http.get>( - `/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}`, - defaultHttpOptionsFromConfig(config)); + fullSearch = false, deprecatedFilter = DeprecatedFilter.ALL, widgetTypes: Array = null, + config?: RequestConfig): Observable> { + let url = + `/api/widgetTypes${pageLink.toQuery()}&tenantOnly=${tenantOnly}&fullSearch=${fullSearch}&deprecatedFilter=${deprecatedFilter}`; + if (widgetTypes && widgetTypes.length) { + url += `&widgetTypeList=${widgetTypes.join(',')}`; + } + return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } public getWidgetTemplate(widgetTypeParam: widgetType, @@ -301,6 +307,5 @@ export class WidgetService { this.systemWidgetsBundles = undefined; this.tenantWidgetsBundles = undefined; this.loadWidgetsBundleCacheSubject = undefined; - this.widgetTypeInfosCache.clear(); } } diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html index 9b5a742ecf..166e359799 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-page.component.html @@ -386,7 +386,7 @@ -
+ (closeSearch)="dashboardWidgetSelectComponent.search = ''"> +
-
+
+ [(ngModel)]="dashboardWidgetSelectComponent.search" + placeholder="{{ ((!dashboardWidgetSelectComponent.widgetsBundle && dashboardWidgetSelectComponent.selectWidgetMode === 'bundles') + ? 'widgets-bundle.search' : 'widget.search') | translate }}">
- - {{ 'widgets-bundle.widgets-bundles' | translate }} {{ 'widget.all-widgets' | translate }} + - {{ 'widget.all' | translate }} - {{ 'widget.actual' | translate }} - {{ 'widget.deprecated' | translate }} + [(ngModel)]="dashboardWidgetSelectComponent.deprecatedFilter"> + {{ 'widget.all' | translate }} + {{ 'widget.actual' | translate }} + {{ 'widget.deprecated' | translate }}
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 a9ce196203..af76812fa1 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 @@ -230,7 +230,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC forceDashboardMobileMode = false; isAddingWidget = false; isAddingWidgetClosed = true; - searchBundle = ''; filterWidgetTypes: widgetType[] = null; isToolbarOpened = false; @@ -1153,7 +1152,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC addWidgetFromType(widget: WidgetInfo) { this.onAddWidgetClosed(); - this.searchBundle = ''; this.widgetComponentService.getWidgetInfo(widget.typeFullFqn).subscribe( (widgetTypeInfo) => { const config: WidgetConfig = this.dashboardUtils.widgetConfigFromWidgetType(widgetTypeInfo); @@ -1426,13 +1424,10 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC return widgetContextActions; } - widgetBundleSelected(){ - this.searchBundle = ''; - } - clearSelectedWidgetBundle() { - this.searchBundle = ''; + this.dashboardWidgetSelectComponent.search = ''; this.dashboardWidgetSelectComponent.widgetsBundle = null; + this.dashboardWidgetSelectComponent.selectWidgetMode = 'bundles'; } editWidgetsTypesToDisplay($event: Event) { @@ -1482,10 +1477,6 @@ export class DashboardPageComponent extends PageComponent implements IDashboardC this.cd.markForCheck(); } - onCloseSearchBundle() { - this.searchBundle = ''; - } - public updateDashboardImage($event: Event) { if ($event) { $event.stopPropagation(); diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html index 44882ab889..a0c7bec2e0 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.html @@ -15,79 +15,105 @@ limitations under the License. --> -
+
-
- -
+ + +
- + - -
-
- -
- {{ widget.title }} -
-
- {{widget.title}}
widget.deprecated
- {{ 'widget.' + widget.type | translate }} - - {{ widget.description }} - -
-
-
-
-
- -
+ + + + + +
+ {{ item.title }} +
+
+ {{item.name}}
widget.deprecated
+ {{ 'widget.' + item.widgetType | translate }} + + {{ item.description }} + +
+
+
+ +
{{ 'widget.loading-widgets' | translate }} - -
-
- - +
+
+ + {{(selectWidgetMode === 'bundles' ? 'widgets-bundle.empty' : 'widget.no-widgets-text') | translate}} + + -
-
- -
- {{ widgetsBundle.title }} -
-
- {{ widgetsBundle.title }} - widgets-bundle.system - - {{ widgetsBundle.description }} - -
-
-
-
+ + + + +
+ {{ item.title }} +
+
+ {{ item.title }} + widgets-bundle.system + + {{ item.description }} + +
+
+
-
{{ 'widgets-bundle.loading-widgets-bundles' | translate }}
- + + widgets-bundle.no-widgets-bundles-text -
+ + +
+
+
+ + + + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss index 3a290e53e5..3641638247 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.scss @@ -13,83 +13,89 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -@import '../../../../../scss/constants'; -:host{ - min-width: 100%; - min-height: 100%; - position: absolute; +.tb-dashboard-widget-select { background-color: #cfd8dc; + position: absolute; + inset: 0; - .widget-select { - padding: 12px 0 12px 12px; - background-color: #cfd8dc; - .mat-card-container { - flex: 0 0 100%; - max-width: 100%; + .mat-mdc-card.tb-widget-preview-card { + cursor: pointer; + transition: box-shadow 0.2s; + padding: 16px; + + &:hover { + box-shadow: 0 2px 6px 6px rgb(0 0 0 / 20%), 0 1px 4px 2px rgb(0 0 0 / 14%), 0 1px 6px 0 rgb(0 0 0 / 12%) + } - &:hover { - .mat-mdc-card { - box-shadow: 0 2px 6px 6px rgb(0 0 0 / 20%), 0 1px 4px 2px rgb(0 0 0 / 14%), 0 1px 6px 0 rgb(0 0 0 / 12%) - } + &.loading-cell { + height: 100%; + min-height: 200px; + + .mat-mdc-card-title { + height: 32px; + margin-bottom: 16px; + } + + .preview-container { + height: 80%; + margin: auto 0; } - .mat-mdc-card { - cursor: pointer; - transition: box-shadow 0.2s; - padding: 16px; + .mat-mdc-card-content { + height: 100%; + margin: 0; + } - .preview-container { - text-align: center; - margin: auto 0; - } + .preview-container, .mat-mdc-card-title, .mat-mdc-card-content { + background: linear-gradient(110deg, #ececec 8%, #f5f5f5 18%, #ececec 33%); + border-radius: 5px; + background-size: 200% 100%; + animation: 1s shine linear infinite; + } + } - .preview { - max-width: 100%; - max-height: 100%; - object-fit: contain; - } + .preview-container { + text-align: center; + margin: auto 0; + } - .mat-mdc-card-title { - font-size: 20px; - line-height: normal; - margin-bottom: 8px; - .tb-deprecated { - font-size: 14px; - color: rgba(209, 39, 48, 0.87); - } - } + .preview { + max-width: 100%; + max-height: 100%; + object-fit: contain; + } - .mat-mdc-card-subtitle { - margin-bottom: 16px; - margin-top: -4px; - line-height: normal; - font-weight: normal; - } + .mat-mdc-card-title { + font-size: 20px; + line-height: normal; + margin-bottom: 8px; - .mat-mdc-card-content { - font-size: 14px; - line-height: 18px; - color: #666; - margin-bottom: 16px; - padding: 0; - } + .tb-deprecated { + font-size: 14px; + color: rgba(209, 39, 48, 0.87); } } - @media #{$mat-gt-xs} { - .mat-card-container { - flex: 0 0 50%; - max-width: 50%; - } + .mat-mdc-card-subtitle { + margin-bottom: 16px; + margin-top: -4px; + line-height: normal; + font-weight: normal; } - @media screen and (min-width: 2000px) { - .mat-card-container { - flex: 0 0 33.333333%; - max-width: 33.333333%; - } + .mat-mdc-card-content { + font-size: 14px; + line-height: 18px; + color: #666; + margin-bottom: 16px; + padding: 0; } } } +@keyframes shine { + to { + background-position-x: -200%; + } +} diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts index 8a359de66c..7f661df575 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/dashboard-widget-select.component.ts @@ -14,74 +14,68 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output } from '@angular/core'; +import { ChangeDetectorRef, Component, EventEmitter, Input, OnInit, Output, ViewEncapsulation } from '@angular/core'; import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { IAliasController } from '@core/api/widget-api.models'; import { NULL_UUID } from '@shared/models/id/has-uuid'; import { WidgetService } from '@core/http/widget.service'; -import { fullWidgetTypeFqn, WidgetInfo, widgetType, WidgetTypeInfo } from '@shared/models/widget.models'; -import { debounceTime, distinctUntilChanged, map, share, switchMap, tap } from 'rxjs/operators'; -import { BehaviorSubject, combineLatest, Observable, of, ReplaySubject } from 'rxjs'; +import { + DeprecatedFilter, + fullWidgetTypeFqn, + WidgetInfo, + widgetType, + WidgetTypeInfo +} from '@shared/models/widget.models'; +import { debounceTime, distinctUntilChanged, map, skip } from 'rxjs/operators'; +import { BehaviorSubject, combineLatest } from 'rxjs'; import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; -import { isDefinedAndNotNull } from '@core/utils'; +import { isDefinedAndNotNull, isObject } from '@core/utils'; import { PageLink } from '@shared/models/page/page-link'; import { Direction } from '@shared/models/page/sort-order'; - -type widgetsListMode = 'all' | 'actual' | 'deprecated'; +import { GridEntitiesFetchFunction, ScrollGridColumns } from '@home/models/datasource/scroll-grid-datasource'; type selectWidgetMode = 'bundles' | 'allWidgets'; +interface WidgetsFilter { + search: string; + filter: widgetType[]; + deprecatedFilter: DeprecatedFilter; +} + +interface BundleWidgetsFilter extends WidgetsFilter { + widgetsBundleId: string; +} + @Component({ selector: 'tb-dashboard-widget-select', templateUrl: './dashboard-widget-select.component.html', - styleUrls: ['./dashboard-widget-select.component.scss'] + styleUrls: ['./dashboard-widget-select.component.scss'], + encapsulation: ViewEncapsulation.None }) export class DashboardWidgetSelectComponent implements OnInit { - private search$ = new BehaviorSubject(''); + private searchSubject = new BehaviorSubject(''); + private search$ = this.searchSubject.asObservable().pipe( + debounceTime(150)); + private filterWidgetTypes$ = new BehaviorSubject>(null); - private widgetsListMode$ = new BehaviorSubject('actual'); + private deprecatedFilter$ = new BehaviorSubject(DeprecatedFilter.ACTUAL); private selectWidgetMode$ = new BehaviorSubject('bundles'); - private widgetsInfo: Observable>; - private widgetsBundleValue: WidgetsBundle; + private widgetsBundle$ = new BehaviorSubject(null); + widgetTypes = new Set(); hasDeprecated = false; - allWidgets$: Observable>; - widgets$: Observable>; - loadingWidgetsSubject: BehaviorSubject = new BehaviorSubject(false); - loadingWidgets$ = this.loadingWidgetsSubject.pipe( - share() - ); - widgetsBundles$: Observable>; - loadingWidgetBundlesSubject: BehaviorSubject = new BehaviorSubject(true); - loadingWidgetBundles$ = this.loadingWidgetBundlesSubject.pipe( - share() - ); - - set widgetsBundle(widgetBundle: WidgetsBundle) { - if (this.widgetsBundleValue !== widgetBundle) { - this.widgetsBundleValue = widgetBundle; - if (widgetBundle === null) { - this.widgetTypes.clear(); - this.hasDeprecated = false; - } - this.filterWidgetTypes$.next(null); - this.widgetsListMode$.next('actual'); - this.widgetsInfo = null; - } - } - - get widgetsBundle(): WidgetsBundle { - return this.widgetsBundleValue; - } - @Input() aliasController: IAliasController; @Input() - set searchBundle(search: string) { - this.search$.next(search); + set search(search: string) { + this.searchSubject.next(search); + } + + get search(): string { + return this.searchSubject.value; } @Input() @@ -95,7 +89,18 @@ export class DashboardWidgetSelectComponent implements OnInit { @Input() set selectWidgetMode(mode: selectWidgetMode) { - this.selectWidgetMode$.next(mode); + if (this.selectWidgetMode$.value !== mode) { + if (mode === 'bundles' && this.widgetsBundle$.value === null) { + this.widgetTypes.clear(); + this.hasDeprecated = false; + } else { + this.widgetTypes = new Set(Object.keys(widgetType).map(t => t as widgetType)); + this.hasDeprecated = true; + } + this.filterWidgetTypes$.next(null); + this.deprecatedFilter$.next(DeprecatedFilter.ACTUAL); + this.selectWidgetMode$.next(mode); + } } get selectWidgetMode(): selectWidgetMode { @@ -103,77 +108,121 @@ export class DashboardWidgetSelectComponent implements OnInit { } @Input() - set widgetsListMode(mode: widgetsListMode) { - this.widgetsListMode$.next(mode); + set deprecatedFilter(filter: DeprecatedFilter) { + this.deprecatedFilter$.next(filter); + } + + get deprecatedFilter(): DeprecatedFilter { + return this.deprecatedFilter$.value; + } + + set widgetsBundle(widgetBundle: WidgetsBundle) { + if (this.widgetsBundle$.value !== widgetBundle) { + if (widgetBundle === null && this.selectWidgetMode$.value !== 'allWidgets') { + this.widgetTypes.clear(); + this.hasDeprecated = false; + } else { + this.widgetTypes = new Set(Object.keys(widgetType).map(t => t as widgetType)); + this.hasDeprecated = true; + } + this.filterWidgetTypes$.next(null); + this.deprecatedFilter$.next(DeprecatedFilter.ACTUAL); + this.widgetsBundle$.next(widgetBundle); + } } - get widgetsListMode(): widgetsListMode { - return this.widgetsListMode$.value; + get widgetsBundle(): WidgetsBundle { + return this.widgetsBundle$.value; } @Output() widgetSelected: EventEmitter = new EventEmitter(); - @Output() - widgetsBundleSelected: EventEmitter = new EventEmitter(); + columns: ScrollGridColumns = { + columns: 1, + breakpoints: { + 'screen and (min-width: 2000px)': 3, + 'screen and (min-width: 600px)': 2 + } + }; + + widgetBundlesFetchFunction: GridEntitiesFetchFunction; + allWidgetsFetchFunction: GridEntitiesFetchFunction; + widgetsFetchFunction: GridEntitiesFetchFunction; + + widgetsBundleFilter = ''; + allWidgetsFilter: WidgetsFilter = {search: '', filter: null, deprecatedFilter: DeprecatedFilter.ACTUAL}; + widgetsFilter: BundleWidgetsFilter = {search: '', filter: null, deprecatedFilter: DeprecatedFilter.ACTUAL, widgetsBundleId: null}; constructor(private widgetsService: WidgetService, - private sanitizer: DomSanitizer, - private cd: ChangeDetectorRef) { - this.widgetsBundles$ = combineLatest([this.search$.asObservable(), this.selectWidgetMode$.asObservable()]).pipe( - distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)), - switchMap(search => this.fetchWidgetBundle(...search)) + private cd: ChangeDetectorRef, + private sanitizer: DomSanitizer) { + + this.widgetBundlesFetchFunction = (pageSize, page, filter) => { + const pageLink = new PageLink(pageSize, page, filter, { + property: 'title', + direction: Direction.ASC + }); + return this.widgetsService.getWidgetBundles(pageLink, true); + }; + + this.allWidgetsFetchFunction = (pageSize, page, filter) => { + const pageLink = new PageLink(pageSize, page, filter.search, { + property: 'name', + direction: Direction.ASC + }); + return this.widgetsService.getWidgetTypes(pageLink, false, true, filter.deprecatedFilter, filter.filter); + }; + + this.widgetsFetchFunction = (pageSize, page, filter) => { + const pageLink = new PageLink(pageSize, page, filter.search, { + property: 'name', + direction: Direction.ASC + }); + return this.widgetsService.getBundleWidgetTypeInfos(pageLink, filter.widgetsBundleId, + true, filter.deprecatedFilter, filter.filter); + }; + + this.search$.pipe( + distinctUntilChanged(), + skip(1) + ).subscribe( + (search) => { + this.widgetsBundleFilter = search; + this.cd.markForCheck(); + } ); - this.allWidgets$ = combineLatest([this.search$.asObservable().pipe( - debounceTime(150) - ), this.selectWidgetMode$.asObservable()]).pipe( - distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)), - switchMap(search => this.fetchAllWidgets(...search)), - share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false }) + + combineLatest({search: this.search$, filter: this.filterWidgetTypes$.asObservable(), + deprecatedFilter: this.deprecatedFilter$.asObservable()}).pipe( + distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)), + skip(1) + ).subscribe( + (filter) => { + this.allWidgetsFilter = filter; + this.cd.markForCheck(); + } ); - this.widgets$ = combineLatest([this.search$.asObservable(), this.filterWidgetTypes$.asObservable(), this.widgetsListMode$]).pipe( + + combineLatest({search: this.search$, widgetsBundleId: this.widgetsBundle$.pipe(map(wb => wb !== null ? wb.id.id : null)), + filter: this.filterWidgetTypes$.asObservable(), deprecatedFilter: this.deprecatedFilter$.asObservable()}).pipe( distinctUntilChanged((oldValue, newValue) => JSON.stringify(oldValue) === JSON.stringify(newValue)), - switchMap(search => this.fetchWidgets(...search)) + skip(1) + ).subscribe( + (filter) => { + if (filter.widgetsBundleId) { + this.widgetsFilter = filter; + this.cd.markForCheck(); + } + } ); } ngOnInit(): void { } - private getWidgets(): Observable> { - if (!this.widgetsInfo) { - if (this.widgetsBundle !== null) { - this.loadingWidgetsSubject.next(true); - this.widgetsInfo = this.widgetsService.getBundleWidgetTypeInfos(this.widgetsBundle.id.id).pipe( - map(widgets => { - const widgetTypes = new Set(); - const hasDeprecated = widgets.some(w => w.deprecated); - const widgetInfos = widgets.map((widgetTypeInfo) => { - widgetTypes.add(widgetTypeInfo.widgetType); - return this.toWidgetInfo(widgetTypeInfo); - } - ); - setTimeout(() => { - this.widgetTypes = widgetTypes; - this.hasDeprecated = hasDeprecated; - this.cd.markForCheck(); - }); - return widgetInfos; - }), - tap(() => { - this.loadingWidgetsSubject.next(false); - }), - share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false }) - ); - } else { - this.widgetsInfo = of([]); - } - } - return this.widgetsInfo; - } - - onWidgetClicked($event: Event, widget: WidgetInfo): void { - this.widgetSelected.emit(widget); + onWidgetClicked($event: Event, widget: WidgetTypeInfo): void { + this.widgetSelected.emit(this.toWidgetInfo(widget)); } isSystem(item: WidgetsBundle): boolean { @@ -183,8 +232,10 @@ export class DashboardWidgetSelectComponent implements OnInit { selectBundle($event: Event, bundle: WidgetsBundle) { $event.preventDefault(); this.widgetsBundle = bundle; - this.search$.next(''); - this.widgetsBundleSelected.emit(bundle); + if (bundle.title?.toLowerCase().includes(this.search.toLowerCase()) || + bundle.description?.toLowerCase().includes(this.search.toLowerCase())) { + this.searchSubject.next(''); + } } getPreviewImage(imageUrl: string | null): SafeUrl | string { @@ -194,62 +245,8 @@ export class DashboardWidgetSelectComponent implements OnInit { return '/assets/widget-preview-empty.svg'; } - private getWidgetsBundles(): Observable> { - return this.widgetsService.getAllWidgetsBundles().pipe( - tap(() => this.loadingWidgetBundlesSubject.next(false)), - share({ connector: () => new ReplaySubject(1), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false }) - ); - } - - private fetchWidgetBundle(search: string, mode: selectWidgetMode): Observable> { - if (mode === 'bundles') { - return this.getWidgetsBundles().pipe( - map(bundles => search ? bundles.filter( - bundle => ( - bundle.title?.toLowerCase().includes(search.toLowerCase()) || - bundle.description?.toLowerCase().includes(search.toLowerCase()) - )) : bundles - ) - ); - } else { - return of([]); - } - } - - private fetchWidgets(search: string, filter: widgetType[], listMode: widgetsListMode): Observable> { - return this.getWidgets().pipe( - map(widgets => (listMode && listMode !== 'all') ? - widgets.filter((widget) => listMode === 'actual' ? !widget.deprecated : widget.deprecated) : widgets), - map(widgets => filter ? widgets.filter((widget) => filter.includes(widget.type)) : widgets), - map(widgets => search ? widgets.filter( - widget => ( - widget.title?.toLowerCase().includes(search.toLowerCase()) || - widget.description?.toLowerCase().includes(search.toLowerCase()) - )) : widgets - ) - ); - } - - private fetchAllWidgets(search: string, mode: selectWidgetMode): Observable> { - if (mode === 'allWidgets') { - const pageLink = new PageLink(1024, 0, search, { - property: 'name', - direction: Direction.ASC - }); - return this.getAllWidgets(pageLink); - } else { - return of([]); - } - } - - private getAllWidgets(pageLink: PageLink): Observable> { - this.loadingWidgetsSubject.next(true); - return this.widgetsService.getWidgetTypes(pageLink, false, true).pipe( - map(data => data.data.map(w => this.toWidgetInfo(w))), - tap(() => { - this.loadingWidgetsSubject.next(false); - }) - ); + isObject(value: any): boolean { + return isObject(value); } private toWidgetInfo(widgetTypeInfo: WidgetTypeInfo): WidgetInfo { diff --git a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.html b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.html new file mode 100644 index 0000000000..5340293a12 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.html @@ -0,0 +1,53 @@ + + + +
+
+ + + + + + +
+
+
+
+ + + + + + + + + + + + +
+ +
+
+ +
+ +
+
diff --git a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss new file mode 100644 index 0000000000..c7a6e2d4b7 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.scss @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2023 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-scroll-grid-viewport { + height: 100%; + .cdk-virtual-scroll-content-wrapper { + display: flex; + flex-direction: column; + } + .cdk-virtual-scroll-spacer { + height: auto !important; + } + .tb-scroll-grid-items-row { + display: flex; + flex-direction: row; + } + .tb-scroll-grid-item-container { + flex: 1; + } +} diff --git a/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts new file mode 100644 index 0000000000..3ca42bba07 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/grid/scroll-grid.component.ts @@ -0,0 +1,103 @@ +/// +/// Copyright © 2016-2023 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 { + AfterViewInit, + Component, + Input, + OnChanges, + OnInit, + Renderer2, + SimpleChanges, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { + GridEntitiesFetchFunction, + ScrollGridColumns, + ScrollGridDatasource +} from '@home/models/datasource/scroll-grid-datasource'; +import { BreakpointObserver } from '@angular/cdk/layout'; +import { isObject } from '@app/core/utils'; +import { CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; + +@Component({ + selector: 'tb-scroll-grid', + templateUrl: './scroll-grid.component.html', + styleUrls: ['./scroll-grid.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ScrollGridComponent implements OnInit, AfterViewInit, OnChanges { + + @ViewChild('viewport') + viewport: CdkVirtualScrollViewport; + + @Input() + columns: ScrollGridColumns = {columns: 1}; + + @Input() + fetchFunction: GridEntitiesFetchFunction; + + @Input() + filter: F; + + @Input() + itemSize = 200; + + @Input() + gap = 12; + + @Input() + itemCard: TemplateRef<{item: T}>; + + @Input() + loadingCell: TemplateRef; + + @Input() + dataLoading: TemplateRef; + + @Input() + noData: TemplateRef; + + dataSource: ScrollGridDatasource; + + constructor(private breakpointObserver: BreakpointObserver, + private renderer: Renderer2) { + } + + ngOnInit(): void { + this.dataSource = new ScrollGridDatasource(this.breakpointObserver, this.columns, this.fetchFunction, this.filter); + } + + ngAfterViewInit() { + this.renderer.setStyle(this.viewport._contentWrapper.nativeElement, 'gap', this.gap + 'px'); + this.renderer.setStyle(this.viewport._contentWrapper.nativeElement, 'padding', this.gap + 'px'); + } + + ngOnChanges(changes: SimpleChanges): void { + for (const propName of Object.keys(changes)) { + const change = changes[propName]; + if (!change.firstChange && change.currentValue !== change.previousValue && propName === 'filter') { + this.dataSource.updateFilter(this.filter); + } + } + } + + isObject(value: any): boolean { + return isObject(value); + } +} 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 735ef9742b..46e9f15275 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 @@ -181,6 +181,7 @@ import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delet import { ExportWidgetsBundleDialogComponent } from '@home/components/import-export/export-widgets-bundle-dialog.component'; +import { ScrollGridComponent } from '@home/components/grid/scroll-grid.component'; @NgModule({ declarations: @@ -325,7 +326,8 @@ import { RateLimitsComponent, RateLimitsTextComponent, RateLimitsDetailsDialogComponent, - SendNotificationButtonComponent + SendNotificationButtonComponent, + ScrollGridComponent ], imports: [ CommonModule, @@ -463,7 +465,8 @@ import { RateLimitsComponent, RateLimitsTextComponent, RateLimitsDetailsDialogComponent, - SendNotificationButtonComponent + SendNotificationButtonComponent, + ScrollGridComponent ], providers: [ WidgetComponentService, diff --git a/ui-ngx/src/app/modules/home/models/datasource/scroll-grid-datasource.ts b/ui-ngx/src/app/modules/home/models/datasource/scroll-grid-datasource.ts new file mode 100644 index 0000000000..b3568b4bc5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/models/datasource/scroll-grid-datasource.ts @@ -0,0 +1,250 @@ +/// +/// Copyright © 2016-2023 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 { DataSource, ListRange } from '@angular/cdk/collections'; +import { CdkVirtualForOf, CdkVirtualScrollViewport } from '@angular/cdk/scrolling'; +import { BehaviorSubject, Observable, of, Subscription } from 'rxjs'; +import { catchError } from 'rxjs/operators'; +import { emptyPageData, PageData } from '@shared/models/page/page-data'; +import { BreakpointObserver } from '@angular/cdk/layout'; + +export type GridEntitiesFetchFunction = (pageSize: number, page: number, filter: F) => Observable>; + +export type GridCellType = 'emptyCell' | 'loadingCell'; + +export interface ScrollGridColumns { + columns: number; + breakpoints?: {[breakpoint: string]: number}; +} + +export class ScrollGridDatasource extends DataSource<(T | GridCellType)[]> { + + public initialDataLoading = true; + + private _data: T[] = []; + private _rows: (T | GridCellType)[][] = Array.from({length: 100000}); + private _hasNext = true; + private _columns: number; + private _viewport: CdkVirtualScrollViewport; + private _pendingRange: ListRange = null; + private _fetchingData = false; + private _fetchSubscription: Subscription; + private _totalElements = 0; + + private _dataStream: BehaviorSubject<(T | GridCellType)[][]>; + private _subscription: Subscription; + + constructor(private breakpointObserver: BreakpointObserver, + private columns: ScrollGridColumns, + private fetchFunction: GridEntitiesFetchFunction, + private filter: F) { + super(); + } + + connect(collectionViewer: CdkVirtualForOf<(T | GridCellType)[]>): Observable<(T | GridCellType)[][]> { + this._viewport = (collectionViewer as any)._viewport; + this._init(); + + if (this.columns.breakpoints) { + const breakpoints = Object.keys(this.columns.breakpoints); + this._subscription.add(this.breakpointObserver.observe(breakpoints).subscribe( + () => { + this._columnsChanged(this._detectColumns()); + } + )); + } + + this._subscription.add( + collectionViewer.viewChange.subscribe(range => this._fetchDataFromRange(range)) + ); + return this._dataStream; + } + + disconnect(): void { + this._reset(); + this._subscription.unsubscribe(); + } + + + get isEmpty(): boolean { + return !this._data.length; + } + + get active(): boolean { + return !!this._subscription && !this._subscription.closed; + } + + public updateFilter(filter: F) { + this.filter = filter; + if (this.active) { + const prevLength = this._rows.length; + this._reset(); + const dataLengthChanged = prevLength !== this._rows.length; + + const range = this._viewport.getRenderedRange(); + + if (dataLengthChanged) { + // Force recalculate new range + if (range.start === 0) { + range.start = 1; + } + this._viewport.appendOnly = false; + } + + const scrollOffset = this._viewport.measureScrollOffset(); + if (scrollOffset > 0) { + this._viewport.scrollToOffset(0); + } + + this._dataUpdated(); + this._viewport.appendOnly = true; + + if (!dataLengthChanged) { + this._fetchDataFromRange(range); + } + } + } + + private _detectColumns(): number { + let columns = this.columns.columns; + if (this.columns.breakpoints) { + for (const breakpont of Object.keys(this.columns.breakpoints)) { + if (this.breakpointObserver.isMatched(breakpont)) { + columns = this.columns.breakpoints[breakpont]; + break; + } + } + } + return columns; + } + + private _init() { + this._subscription = new Subscription(); + this._columns = this._detectColumns(); + if (this._dataStream) { + this._dataStream.complete(); + } + this._dataStream = new BehaviorSubject(this._rows); + } + + private _reset() { + this._data = []; + this._totalElements = 0; + this.initialDataLoading = true; + this._rows = Array.from({length: 100000}); + this._hasNext = true; + this._pendingRange = null; + this._fetchingData = false; + if (this._fetchSubscription) { + this._fetchSubscription.unsubscribe(); + } + } + + private _columnsChanged(columns: number) { + if (this._columns !== columns) { + const fetchData = columns > this._columns; + this._columns = columns; + const rowsLength = this._totalElements ? Math.ceil(this._totalElements / this._columns) : 100000; + this._rows = Array.from({length: rowsLength}); + this._dataUpdated(); + if (fetchData && this._hasNext) { + this._fetchDataFromRange(this._viewport.getRenderedRange()); + } + } + } + + private _fetchDataFromRange(range: ListRange) { + if (this._hasNext) { + if (this._fetchingData) { + this._pendingRange = range; + } else { + const endIndex = (range.end + 1) * this._columns; + if (endIndex > this._data.length) { + const startIndex = this._data.length; + const minPageSize = endIndex - startIndex; + const maxPageSize = minPageSize * 2; + let pageSize = minPageSize; + let page = Math.floor(startIndex / pageSize); + while (startIndex % pageSize !== 0 && pageSize <= maxPageSize) { + if (((page + 1) * pageSize) > endIndex) { + break; + } + pageSize++; + page = Math.floor(startIndex / pageSize); + } + const offset = startIndex % pageSize; + this._fetchData(offset, pageSize, page); + } + } + } + } + + private _fetchData(offset: number, pageSize: number, page: number) { + this._fetchingData = true; + this._fetchSubscription = this.fetchFunction(pageSize, page, this.filter).pipe( + catchError(() => of(emptyPageData())) + ).subscribe( + (data) => { + this._hasNext = data.hasNext; + if (data.data.length > offset) { + for (let i = offset; i < data.data.length; i++) { + this._data.push(data.data[i]); + } + } + this._totalElements = data.totalElements; + const rowsLength = this._totalElements ? Math.ceil(this._totalElements / this._columns) : 100000; + this._rows = Array.from({length: rowsLength}); + this._dataUpdated(); + this.initialDataLoading = false; + this._fetchingData = false; + if (this._pendingRange) { + const range = this._pendingRange; + this._pendingRange = null; + this._fetchDataFromRange(range); + } + } + ); + } + + private _dataUpdated() { + for (let index = 0; index < this._data.length; index++) { + const row = Math.floor(index / this._columns); + const col = index % this._columns; + if (!this._rows[row]) { + this._rows[row] = []; + } + this._rows[row][col] = this._data[index]; + } + this._fillGridCells(); + this._dataStream.next(this._rows); + } + + private _fillGridCells() { + if (this._totalElements) { + const startIndex = this._data.length; + const endIndex = this._rows.length * this._columns; + for (let index = startIndex; index < endIndex; index++) { + const row = Math.floor(index / this._columns); + const col = index % this._columns; + const cellType: GridCellType = index < this._totalElements ? 'loadingCell' : 'emptyCell'; + if (!this._rows[row]) { + this._rows[row] = []; + } + this._rows[row][col] = cellType; + } + } + } +} 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 214a78d022..61b4713cc4 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 @@ -516,6 +516,7 @@ export interface WidgetInfo extends WidgetTypeDescriptor, WidgetControllerDescri typeLatestDataKeySettingsSchema?: string | any; image?: string; description?: string; + tags?: string[]; componentType?: Type; componentModuleRef?: NgModuleRef; } @@ -632,6 +633,7 @@ export const detailsToWidgetInfo = (widgetTypeDetailsEntity: WidgetTypeDetails): const widgetInfo = toWidgetInfo(widgetTypeDetailsEntity); widgetInfo.image = widgetTypeDetailsEntity.image; widgetInfo.description = widgetTypeDetailsEntity.description; + widgetInfo.tags = widgetTypeDetailsEntity.tags; return widgetInfo; }; @@ -672,6 +674,7 @@ export const toWidgetTypeDetails = (widgetInfo: WidgetInfo, id: WidgetTypeId, te return { ...widgetTypeEntity, description: widgetInfo.description, + tags: widgetInfo.tags, image: widgetInfo.image }; }; diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html index f19edc35c7..f3410f9893 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.html @@ -253,6 +253,11 @@ rows="2" maxlength="255"> {{descriptionInput.value?.length || 0}}/255 + + diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts index 4ac54e7a68..4c3c933f82 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts @@ -58,7 +58,7 @@ export class WidgetsBundleWidgetsResolver implements Resolve> { const widgetsBundleId = route.params.widgetsBundleId; - return this.widgetsService.getBundleWidgetTypeInfos(widgetsBundleId); + return this.widgetsService.getBundleWidgetTypeInfosList(widgetsBundleId); } } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html index b7c23c415d..19309e8660 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html @@ -58,6 +58,10 @@ {{descriptionInput.value?.length || 0}}/1024 + + {{ 'widget.deprecated' | translate }} diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts index 5418557631..e6354945d7 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.ts @@ -52,6 +52,7 @@ export class WidgetTypeComponent extends EntityComponent { name: [entity ? entity.name : '', [Validators.required, Validators.maxLength(255)]], image: [entity ? entity.image : ''], description: [entity ? entity.description : '', Validators.maxLength(1024)], + tags: [entity ? entity.tags : []], deprecated: [entity ? entity.deprecated : false] } ); @@ -62,6 +63,7 @@ export class WidgetTypeComponent extends EntityComponent { name: entity.name, image: entity.image, description: entity.description, + tags: entity.tags, deprecated: entity.deprecated }); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts index f368650aa5..58403ad9b2 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts @@ -152,7 +152,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn cancel() { if (this.isDirty) { - this.widgetsService.getBundleWidgetTypeInfos(this.widgetsBundle.id.id).subscribe( + this.widgetsService.getBundleWidgetTypeInfosList(this.widgetsBundle.id.id).subscribe( (widgets) => { this.widgets = [...widgets]; this.isDirty = false; diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index a08d8837f5..d10bbc433d 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -232,12 +232,20 @@ export interface WidgetType extends BaseWidgetType { export interface WidgetTypeInfo extends BaseWidgetType { image: string; description: string; + tags: string[]; widgetType: widgetType; } export interface WidgetTypeDetails extends WidgetType, ExportableEntity { image: string; description: string; + tags: string[]; +} + +export enum DeprecatedFilter { + ALL = 'ALL', + ACTUAL = 'ACTUAL', + DEPRECATED = 'DEPRECATED' } export enum LegendDirection { 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 0867f21114..536b4fb5e5 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4789,6 +4789,7 @@ "latest-datakey-settings-schema": "Latest data key settings schema", "widget-settings": "Widget settings", "description": "Description", + "tags": "Tags", "image-preview": "Image preview", "settings-form-selector": "Settings form selector", "data-key-settings-form-selector": "Data key settings form selector", From 57968eeb42fa5c9e5bb5a72252cffb3af6c4e40f Mon Sep 17 00:00:00 2001 From: Mr-Mime <37423773+Mr-Mime@users.noreply.github.com> Date: Thu, 28 Sep 2023 23:02:19 +0200 Subject: [PATCH 110/267] Update locale.constant-de_DE.json --- ui-ngx/src/assets/locale/locale.constant-de_DE.json | 4 ++++ 1 file changed, 4 insertions(+) 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 1ce02e0d23..ab02231180 100644 --- a/ui-ngx/src/assets/locale/locale.constant-de_DE.json +++ b/ui-ngx/src/assets/locale/locale.constant-de_DE.json @@ -10,6 +10,10 @@ "permission-denied": "Zugriff verweigert", "permission-denied-text": "Sie haben keine Berechtigung, um diesen Vorgang auszuführen!" }, + "account": { + "account": "Benutzerkonto", + "notification-settings": "Benachrichtigungseinstellungen" + }, "action": { "activate": "Aktivieren", "suspend": "Unterbrechen", From 4dd0d7aaca6e0ec6a95a20f664f8ec91aecd103d Mon Sep 17 00:00:00 2001 From: devaskim Date: Sun, 1 Oct 2023 11:26:05 +0500 Subject: [PATCH 111/267] Use translation placeholder for closing button in embed dialog. --- .../widget/dialog/embed-dashboard-dialog.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html index 36837414ed..e45da616f3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/dialog/embed-dashboard-dialog.component.html @@ -35,7 +35,7 @@ type="button" [disabled]="(isLoading$ | async)" (click)="close()" cdkFocusInitial> - Close + {{ 'action.close' | translate }}
From 0c1e5393dff67686a377f55b0b4f9e4f9c3b6574 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 3 Oct 2023 19:18:34 +0300 Subject: [PATCH 112/267] Replace copy-paste with the correct library --- dao/pom.xml | 4 + .../model/sql/WidgetTypeDetailsEntity.java | 3 +- .../dao/model/sql/WidgetTypeInfoEntity.java | 2 +- .../sql/widget/WidgetTypeInfoRepository.java | 2 +- .../dao/util/mapping/AbstractArrayType.java | 45 --- .../mapping/AbstractArrayTypeDescriptor.java | 119 ------- .../util/mapping/ArraySqlTypeDescriptor.java | 86 ----- .../server/dao/util/mapping/ArrayUtil.java | 335 ------------------ .../mapping/ParameterizedParameterType.java | 64 ---- .../dao/util/mapping/StringArrayType.java | 41 --- .../mapping/StringArrayTypeDescriptor.java | 31 -- pom.xml | 6 + 12 files changed, 13 insertions(+), 725 deletions(-) delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayType.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java delete mode 100644 dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java diff --git a/dao/pom.xml b/dao/pom.xml index e90694f22e..673a08e0c1 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -230,6 +230,10 @@ org.thingsboard.rule-engine rule-engine-api + + io.hypersistence + hypersistence-utils-hibernate-55 + diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java index 99555393c6..eec70be387 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeDetailsEntity.java @@ -16,17 +16,16 @@ package org.thingsboard.server.dao.model.sql; import com.fasterxml.jackson.databind.JsonNode; +import io.hypersistence.utils.hibernate.type.array.StringArrayType; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.id.WidgetTypeId; -import org.thingsboard.server.common.data.id.WidgetsBundleId; import org.thingsboard.server.common.data.widget.BaseWidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeDetails; import org.thingsboard.server.dao.model.ModelConstants; import org.thingsboard.server.dao.util.mapping.JsonStringType; -import org.thingsboard.server.dao.util.mapping.StringArrayType; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java index 2422373c63..fa6fd895cd 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.dao.model.sql; +import io.hypersistence.utils.hibernate.type.array.StringArrayType; import lombok.Data; import lombok.EqualsAndHashCode; import org.hibernate.annotations.Immutable; @@ -23,7 +24,6 @@ import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.widget.BaseWidgetType; import org.thingsboard.server.common.data.widget.WidgetTypeInfo; import org.thingsboard.server.dao.model.ModelConstants; -import org.thingsboard.server.dao.util.mapping.StringArrayType; import javax.persistence.Column; import javax.persistence.Entity; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java index 27f4ef918f..f3f3bf5139 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java @@ -37,7 +37,7 @@ public interface WidgetTypeInfoRepository extends JpaRepository - extends AbstractSingleColumnStandardBasicType - implements DynamicParameterizedType { - - public static final String SQL_ARRAY_TYPE = "sql_array_type"; - - public AbstractArrayType(AbstractArrayTypeDescriptor arrayTypeDescriptor) { - super( - ArraySqlTypeDescriptor.INSTANCE, - arrayTypeDescriptor - ); - } - - @Override - protected boolean registerUnderJavaType() { - return true; - } - - @Override - public void setParameterValues(Properties parameters) { - ((AbstractArrayTypeDescriptor) getJavaTypeDescriptor()).setParameterValues(parameters); - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java deleted file mode 100644 index 91e426567c..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/AbstractArrayTypeDescriptor.java +++ /dev/null @@ -1,119 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -import org.hibernate.HibernateException; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; -import org.hibernate.type.descriptor.java.MutabilityPlan; -import org.hibernate.type.descriptor.java.MutableMutabilityPlan; -import org.hibernate.usertype.DynamicParameterizedType; - -import java.sql.Array; -import java.sql.SQLException; -import java.util.Arrays; -import java.util.Properties; - -import static org.thingsboard.server.dao.util.mapping.AbstractArrayType.SQL_ARRAY_TYPE; - -public abstract class AbstractArrayTypeDescriptor - extends AbstractTypeDescriptor implements DynamicParameterizedType { - - private Class arrayObjectClass; - - private String sqlArrayType; - - public AbstractArrayTypeDescriptor(Class arrayObjectClass) { - this(arrayObjectClass, (MutabilityPlan) new MutableMutabilityPlan() { - @Override - protected T deepCopyNotNull(Object value) { - return ArrayUtil.deepCopy(value); - } - }); - } - - protected AbstractArrayTypeDescriptor(Class arrayObjectClass, MutabilityPlan mutableMutabilityPlan) { - super(arrayObjectClass, mutableMutabilityPlan); - this.arrayObjectClass = arrayObjectClass; - } - - public Class getArrayObjectClass() { - return arrayObjectClass; - } - - public void setArrayObjectClass(Class arrayObjectClass) { - this.arrayObjectClass = arrayObjectClass; - } - - @Override - public void setParameterValues(Properties parameters) { - if (parameters.containsKey(PARAMETER_TYPE)) { - arrayObjectClass = ((ParameterType) parameters.get(PARAMETER_TYPE)).getReturnedClass(); - } - sqlArrayType = parameters.getProperty(SQL_ARRAY_TYPE); - } - - @Override - public boolean areEqual(T one, T another) { - if (one == another) { - return true; - } - if (one == null || another == null) { - return false; - } - return ArrayUtil.isEquals(one, another); - } - - @Override - public String toString(T value) { - return Arrays.deepToString(ArrayUtil.wrapArray(value)); - } - - @Override - public T fromString(String string) { - return ArrayUtil.fromString(string, arrayObjectClass); - } - - @Override - public String extractLoggableRepresentation(T value) { - return (value == null) ? "null" : toString(value); - } - - @SuppressWarnings({"unchecked"}) - @Override - public X unwrap(T value, Class type, WrapperOptions options) { - return (X) ArrayUtil.wrapArray(value); - } - - @Override - public T wrap(X value, WrapperOptions options) { - if (value instanceof Array) { - Array array = (Array) value; - try { - return ArrayUtil.unwrapArray((Object[]) array.getArray(), arrayObjectClass); - } catch (SQLException e) { - throw new HibernateException( - new IllegalArgumentException(e) - ); - } - } - return (T) value; - } - - protected String getSqlArrayType() { - return sqlArrayType; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java deleted file mode 100644 index 4baa150445..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArraySqlTypeDescriptor.java +++ /dev/null @@ -1,86 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -import org.hibernate.type.descriptor.ValueBinder; -import org.hibernate.type.descriptor.ValueExtractor; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.sql.BasicBinder; -import org.hibernate.type.descriptor.sql.BasicExtractor; -import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; - -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; - -public class ArraySqlTypeDescriptor implements SqlTypeDescriptor { - - public static final ArraySqlTypeDescriptor INSTANCE = new ArraySqlTypeDescriptor(); - - @Override - public int getSqlType() { - return Types.ARRAY; - } - - @Override - public boolean canBeRemapped() { - return true; - } - - @Override - public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicBinder(javaTypeDescriptor, this) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - AbstractArrayTypeDescriptor abstractArrayTypeDescriptor = (AbstractArrayTypeDescriptor) javaTypeDescriptor; - st.setArray(index, st.getConnection().createArrayOf( - abstractArrayTypeDescriptor.getSqlArrayType(), - abstractArrayTypeDescriptor.unwrap(value, Object[].class, options) - )); - } - - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - throw new UnsupportedOperationException("Binding by name is not supported!"); - } - }; - } - - @Override - public ValueExtractor getExtractor(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicExtractor(javaTypeDescriptor, this) { - @Override - protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap(rs.getArray(name), options); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap(statement.getArray(index), options); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException { - return javaTypeDescriptor.wrap(statement.getArray(name), options); - } - }; - } - -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java deleted file mode 100644 index eb940c1912..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ArrayUtil.java +++ /dev/null @@ -1,335 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -import java.lang.reflect.Array; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.List; - -public class ArrayUtil { - - public static T deepCopy(Object originalArray) { - Class arrayClass = originalArray.getClass(); - - if (boolean[].class.equals(arrayClass)) { - boolean[] array = (boolean[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (byte[].class.equals(arrayClass)) { - byte[] array = (byte[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (short[].class.equals(arrayClass)) { - short[] array = (short[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (int[].class.equals(arrayClass)) { - int[] array = (int[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (long[].class.equals(arrayClass)) { - long[] array = (long[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (float[].class.equals(arrayClass)) { - float[] array = (float[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (double[].class.equals(arrayClass)) { - double[] array = (double[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else if (char[].class.equals(arrayClass)) { - char[] array = (char[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } else { - Object[] array = (Object[]) originalArray; - return (T) Arrays.copyOf(array, array.length); - } - } - - public static Object[] wrapArray(Object originalArray) { - Class arrayClass = originalArray.getClass(); - - if (boolean[].class.equals(arrayClass)) { - boolean[] fromArray = (boolean[]) originalArray; - Boolean[] array = new Boolean[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (byte[].class.equals(arrayClass)) { - byte[] fromArray = (byte[]) originalArray; - Byte[] array = new Byte[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (short[].class.equals(arrayClass)) { - short[] fromArray = (short[]) originalArray; - Short[] array = new Short[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (int[].class.equals(arrayClass)) { - int[] fromArray = (int[]) originalArray; - Integer[] array = new Integer[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (long[].class.equals(arrayClass)) { - long[] fromArray = (long[]) originalArray; - Long[] array = new Long[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (float[].class.equals(arrayClass)) { - float[] fromArray = (float[]) originalArray; - Float[] array = new Float[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (double[].class.equals(arrayClass)) { - double[] fromArray = (double[]) originalArray; - Double[] array = new Double[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (char[].class.equals(arrayClass)) { - char[] fromArray = (char[]) originalArray; - Character[] array = new Character[fromArray.length]; - for (int i = 0; i < fromArray.length; i++) { - array[i] = fromArray[i]; - } - return array; - } else if (originalArray instanceof Collection) { - return ((Collection) originalArray).toArray(); - } else { - return (Object[]) originalArray; - } - } - - public static T unwrapArray(Object[] originalArray, Class arrayClass) { - - if (boolean[].class.equals(arrayClass)) { - boolean[] array = new boolean[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Boolean) originalArray[i] : Boolean.FALSE; - } - return (T) array; - } else if (byte[].class.equals(arrayClass)) { - byte[] array = new byte[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Byte) originalArray[i] : 0; - } - return (T) array; - } else if (short[].class.equals(arrayClass)) { - short[] array = new short[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Short) originalArray[i] : 0; - } - return (T) array; - } else if (int[].class.equals(arrayClass)) { - int[] array = new int[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Integer) originalArray[i] : 0; - } - return (T) array; - } else if (long[].class.equals(arrayClass)) { - long[] array = new long[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Long) originalArray[i] : 0L; - } - return (T) array; - } else if (float[].class.equals(arrayClass)) { - float[] array = new float[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? ((Number) originalArray[i]).floatValue() : 0f; - } - return (T) array; - } else if (double[].class.equals(arrayClass)) { - double[] array = new double[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Double) originalArray[i] : 0d; - } - return (T) array; - } else if (char[].class.equals(arrayClass)) { - char[] array = new char[originalArray.length]; - for (int i = 0; i < originalArray.length; i++) { - array[i] = originalArray[i] != null ? (Character) originalArray[i] : 0; - } - return (T) array; - } else if (Enum[].class.isAssignableFrom(arrayClass)) { - T array = arrayClass.cast(Array.newInstance(arrayClass.getComponentType(), originalArray.length)); - for (int i = 0; i < originalArray.length; i++) { - Object objectValue = originalArray[i]; - if (objectValue != null) { - String stringValue = (objectValue instanceof String) ? (String) objectValue : String.valueOf(objectValue); - objectValue = Enum.valueOf((Class) arrayClass.getComponentType(), stringValue); - } - Array.set(array, i, objectValue); - } - return array; - } else if (java.time.LocalDate[].class.equals(arrayClass) && java.sql.Date[].class.equals(originalArray.getClass())) { - // special case because conversion is neither with ctor nor valueOf - Object[] array = (Object[]) Array.newInstance(java.time.LocalDate.class, originalArray.length); - for (int i = 0; i < array.length; ++i) { - array[i] = originalArray[i] != null ? ((java.sql.Date) originalArray[i]).toLocalDate() : null; - } - return (T) array; - } else if (java.time.LocalDateTime[].class.equals(arrayClass) && java.sql.Timestamp[].class.equals(originalArray.getClass())) { - // special case because conversion is neither with ctor nor valueOf - Object[] array = (Object[]) Array.newInstance(java.time.LocalDateTime.class, originalArray.length); - for (int i = 0; i < array.length; ++i) { - array[i] = originalArray[i] != null ? ((java.sql.Timestamp) originalArray[i]).toLocalDateTime() : null; - } - return (T) array; - } else if(arrayClass.getComponentType() != null && arrayClass.getComponentType().isArray()) { - int arrayLength = originalArray.length; - Object[] array = (Object[]) Array.newInstance(arrayClass.getComponentType(), arrayLength); - if (arrayLength > 0) { - for (int i = 0; i < originalArray.length; i++) { - array[i] = unwrapArray((Object[]) originalArray[i], arrayClass.getComponentType()); - } - } - return (T) array; - } else { - if (arrayClass.isInstance(originalArray)) { - return (T) originalArray; - } else { - return (T) Arrays.copyOf(originalArray, originalArray.length, (Class) arrayClass); - } - } - } - - public static T fromString(String string, Class arrayClass) { - String stringArray = string.replaceAll("[\\[\\]]", ""); - String[] tokens = stringArray.split(","); - - int length = tokens.length; - - if (boolean[].class.equals(arrayClass)) { - boolean[] array = new boolean[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Boolean.valueOf(tokens[i]); - } - return (T) array; - } else if (byte[].class.equals(arrayClass)) { - byte[] array = new byte[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Byte.valueOf(tokens[i]); - } - return (T) array; - } else if (short[].class.equals(arrayClass)) { - short[] array = new short[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Short.valueOf(tokens[i]); - } - return (T) array; - } else if (int[].class.equals(arrayClass)) { - int[] array = new int[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Integer.valueOf(tokens[i]); - } - return (T) array; - } else if (long[].class.equals(arrayClass)) { - long[] array = new long[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Long.valueOf(tokens[i]); - } - return (T) array; - } else if (float[].class.equals(arrayClass)) { - float[] array = new float[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Float.valueOf(tokens[i]); - } - return (T) array; - } else if (double[].class.equals(arrayClass)) { - double[] array = new double[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = Double.valueOf(tokens[i]); - } - return (T) array; - } else if (char[].class.equals(arrayClass)) { - char[] array = new char[length]; - for (int i = 0; i < tokens.length; i++) { - array[i] = tokens[i].length() > 0 ? tokens[i].charAt(0) : Character.MIN_VALUE; - } - return (T) array; - } else { - return (T) tokens; - } - } - - public static boolean isEquals(Object firstArray, Object secondArray) { - if (firstArray.getClass() != secondArray.getClass()) { - return false; - } - Class arrayClass = firstArray.getClass(); - - if (boolean[].class.equals(arrayClass)) { - return Arrays.equals((boolean[]) firstArray, (boolean[]) secondArray); - } else if (byte[].class.equals(arrayClass)) { - return Arrays.equals((byte[]) firstArray, (byte[]) secondArray); - } else if (short[].class.equals(arrayClass)) { - return Arrays.equals((short[]) firstArray, (short[]) secondArray); - } else if (int[].class.equals(arrayClass)) { - return Arrays.equals((int[]) firstArray, (int[]) secondArray); - } else if (long[].class.equals(arrayClass)) { - return Arrays.equals((long[]) firstArray, (long[]) secondArray); - } else if (float[].class.equals(arrayClass)) { - return Arrays.equals((float[]) firstArray, (float[]) secondArray); - } else if (double[].class.equals(arrayClass)) { - return Arrays.equals((double[]) firstArray, (double[]) secondArray); - } else if (char[].class.equals(arrayClass)) { - return Arrays.equals((char[]) firstArray, (char[]) secondArray); - } else { - return Arrays.equals((Object[]) firstArray, (Object[]) secondArray); - } - } - - public static Class toArrayClass(Class arrayElementClass) { - - if (boolean.class.equals(arrayElementClass)) { - return (Class) boolean[].class; - } else if (byte.class.equals(arrayElementClass)) { - return (Class) byte[].class; - } else if (short.class.equals(arrayElementClass)) { - return (Class) short[].class; - } else if (int.class.equals(arrayElementClass)) { - return (Class) int[].class; - } else if (long.class.equals(arrayElementClass)) { - return (Class) long[].class; - } else if (float.class.equals(arrayElementClass)) { - return (Class) float[].class; - } else if (double[].class.equals(arrayElementClass)) { - return (Class) double[].class; - } else if (char[].class.equals(arrayElementClass)) { - return (Class) char[].class; - } else { - Object array = Array.newInstance(arrayElementClass, 0); - return (Class) array.getClass(); - } - } - - public static List asList(T[] array) { - List list = new ArrayList(array.length); - for (int i = 0; i < array.length; i++) { - list.add(i, array[i]); - } - return list; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java deleted file mode 100644 index 53faf75720..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/ParameterizedParameterType.java +++ /dev/null @@ -1,64 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -import org.hibernate.usertype.DynamicParameterizedType; - -import java.lang.annotation.Annotation; - -public class ParameterizedParameterType implements DynamicParameterizedType.ParameterType { - - private final Class clasz; - - public ParameterizedParameterType(Class clasz) { - this.clasz = clasz; - } - - @Override - public Class getReturnedClass() { - return clasz; - } - - @Override - public Annotation[] getAnnotationsMethod() { - return new Annotation[0]; - } - - @Override - public String getCatalog() { - throw new UnsupportedOperationException(); - } - - @Override - public String getSchema() { - throw new UnsupportedOperationException(); - } - - @Override - public String getTable() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isPrimaryKey() { - throw new UnsupportedOperationException(); - } - - @Override - public String[] getColumns() { - throw new UnsupportedOperationException(); - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java deleted file mode 100644 index cd2ee52a35..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayType.java +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -import org.hibernate.usertype.DynamicParameterizedType; -import java.util.Properties; - -public class StringArrayType extends AbstractArrayType { - - public static final StringArrayType INSTANCE = new StringArrayType(); - - public StringArrayType() { - super( - new StringArrayTypeDescriptor() - ); - } - - public StringArrayType(Class arrayClass) { - this(); - Properties parameters = new Properties(); - parameters.put(DynamicParameterizedType.PARAMETER_TYPE, new ParameterizedParameterType(arrayClass)); - setParameterValues(parameters); - } - - public String getName() { - return "string-array"; - } -} diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java b/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java deleted file mode 100644 index 8846d0a5e2..0000000000 --- a/dao/src/main/java/org/thingsboard/server/dao/util/mapping/StringArrayTypeDescriptor.java +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright © 2016-2023 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.util.mapping; - -public class StringArrayTypeDescriptor - extends AbstractArrayTypeDescriptor { - - public StringArrayTypeDescriptor() { - super(String[].class); - } - - @Override - protected String getSqlArrayType() { - String sqlArrayType = super.getSqlArrayType(); - return sqlArrayType != null ? sqlArrayType : "text"; - } -} - diff --git a/pom.xml b/pom.xml index 0344ced04e..05b2d9455f 100755 --- a/pom.xml +++ b/pom.xml @@ -121,6 +121,7 @@ 3.4.0 8.17.0 6.0.20.Final + 3.5.2 3.0.0 2.0.1.Final 1.7.2 @@ -1923,6 +1924,11 @@ hibernate-validator ${hibernate-validator.version} + + io.hypersistence + hypersistence-utils-hibernate-55 + ${hypersistence-utils.version} + org.glassfish javax.el From e7f9171b3877ab319894f5d4a863088456de03ed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javier=20N=C3=BA=C3=B1ez?= Date: Wed, 4 Oct 2023 09:41:28 +0200 Subject: [PATCH 113/267] Update es_ES locale to 3.6 --- .../assets/locale/locale.constant-es_ES.json | 1124 ++++++++++++++++- 1 file changed, 1078 insertions(+), 46 deletions(-) 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 143bed648b..782284792d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -10,11 +10,16 @@ "permission-denied": "Permiso Denegado", "permission-denied-text": "No tienes suficientes derechos para realizar esta operación!" }, + "account": { + "account": "Cuenta", + "notification-settings": "Ajustes de notificaciones" + }, "action": { "activate": "Activar", "suspend": "Suspender", "save": "Guardar", "saveAs": "Guardar como", + "move": "Mover", "cancel": "Cancelar", "ok": "OK", "delete": "Borrar", @@ -35,6 +40,7 @@ "edit-mode": "Modo Edición", "enter-edit-mode": "Modo Edición", "decline-changes": "Descartar cambios", + "decline": "Descartar", "close": "Cerrar", "back": "Atrás", "run": "Ejecutar", @@ -66,7 +72,12 @@ "more": "Más", "less": "Menos", "skip": "Saltar", - "send": "Enviar" + "send": "Enviar", + "reset": "Reset", + "show-more": "Mostrar más", + "dont-show-again": "No volver a mostrar", + "see-documentation": "Ver documentación", + "clear": "Borrar" }, "aggregation": { "aggregation": "Agrupación", @@ -173,6 +184,7 @@ "domain-name-unique": "El nombre de dominio y protocolo debe ser único.", "domain-name-max-length": "El nombre de dominio debe ser menor que 256", "error-verification-url": "Un nombre de dominio no debe contener símbolos '/' y ':'. Ejemplo: thingsboard.io", + "connection-settings": "Ajustes de conexión", "oauth2": { "access-token-uri": "URI Access token", "access-token-uri-required": "Se requere URI Access token.", @@ -263,7 +275,28 @@ "platform-android": "Android", "platform-ios": "iOS", "all-platforms": "Todas las plataformas", - "allowed-platforms": "Plataformas permitidas" + "smtp-provider": "Proveedor SMTP", + "allowed-platforms": "Plataformas permitidas", + "authentication": "Autenticación", + "basic": "Básica", + "provider": "Proveedor", + "redirect-url": "URL Redirección", + "domain-name": "Nombre de dominio", + "redirect-url-template": "Plantilla de redirección (URI)", + "microsoft-tenant-id": "Microsoft tenant ID", + "microsoft-tenant-id-required": "Se requiere tenant ID", + "token-uri": "URI Token", + "token-uri-required": "Se requiere URI token", + "redirect-uri": "URI Redirección", + "google-provider": "Google", + "microsoft-provider": "Office 365", + "sendgrid-provider": "Sendgrid", + "custom-provider": "Personalizado", + "generate-access-token": "Generar token de acceso", + "update-access-token": "Actualizar token de acceso", + "access-token-status": "Estado token:", + "token-status-generated": "Generado", + "token-status-not-generated": "No generado" }, "smpp-provider": { "smpp-version": "Versión SMPP", @@ -481,6 +514,7 @@ "severity-indeterminate": "Indeterminada", "acknowledge": "Reconocer", "clear": "Normalizar", + "delete": "Borrar", "search": "Buscar alarmas", "selected-alarms": "{ count, plural, =1 {1 alarma} other {# alarmas} } seleccionadas", "no-data": "Sin datos que mostrar", @@ -491,10 +525,14 @@ "aknowledge-alarms-text": "Estas seguro de reconocer { count, plural, =1 {1 alarma} other {# alarmas} }?", "aknowledge-alarm-title": "Recononcer Alarma", "aknowledge-alarm-text": "Estas seguro de reconocer Alarma?", + "selected-alarms-are-acknowledged": "Las alarmas seleccionadas ya están reconocidas", "clear-alarms-title": "Normalizar { count, plural, =1 {1 alarma} other {# alarmas} }", "clear-alarms-text": "Limpiar { count, plural, =1 {1 alarma} other {# alarmas} }?", "clear-alarm-title": "Limpiar Alarma", "clear-alarm-text": "Limpiar Alarma?", + "delete-alarms-title": "Delete { count, plural, =1 {1 alarm} other {# alarms} }", + "delete-alarms-text": "Are you sure you want to delete { count, plural, =1 {1 alarm} other {# alarms} }?", + "selected-alarms-are-cleared": "Selected alarms are already cleared", "alarm-status-filter": "Filtro de estados de Alarmas", "alarm-filter-title": "Filtros de alarmas", "assigned": "Asignadas", @@ -512,7 +550,11 @@ "search-propagated-alarms": "Buscar alarmas propagadas", "comments": "Comentarios de alarma", "show-more": "Mostrar más", - "additional-info": "Información adicional" + "additional-info": "Información adicional", + "alarm-type": "Tipo de alarma", + "enter-alarm-type": "Introduce tipo de alarma", + "no-alarm-types-matching": "No se han encontrado tipos de alarma que coincidan con '{{entitySubtype}}'.", + "alarm-type-list-empty": "No se han seleccionado tipos de alarma." }, "alarm-activity": { "add": "Añadir comentario...", @@ -666,6 +708,7 @@ "attribute": { "attributes": "Atributos", "latest-telemetry": "Última telemetría", + "no-latest-telemetry": "No hay última telemetría", "attributes-scope": "Alcance de los atributos del dispositivo", "scope-telemetry": "Telemetría", "scope-latest-telemetry": "Última telemetría", @@ -679,6 +722,8 @@ "key-required": "Clave del atributo requerida.", "value": "Valor", "value-required": "Valor del atributo requerido.", + "telemetry-key-required": "Se requiere clave de telemetría", + "telemetry-value-required": "Se requiere valor Telemetry value is required", "delete-attributes-title": "¿Eliminar { count, plural, =1 {1 atributo} other {# atributos} }?", "delete-attributes-text": "Atención, tras la confirmación el atributo será eliminado, y la información relacionada será irrecuperable.", "delete-attributes": "Borrar atributo", @@ -694,7 +739,19 @@ "no-attributes-text": "No se encontró ningún atributo", "no-telemetry-text": "No se encontró ninguna telemetría", "copy-key": "Copiar clave", - "copy-value": "Copiar valor" + "add-telemetry": "Añadir telemetría", + "copy-value": "Copiar valor", + "delete-timeseries": { + "start-time": "Hora de inicio", + "ends-on": "Fin", + "strategy": "Estrategia", + "delete-strategy": "Estrategia de borrado", + "all-data": "Borrar todos los datos", + "all-data-except-latest-value": "Borrar todos los datos salvo los últimos valores", + "latest-value": "Borrar último valor", + "all-data-for-time-period": "Borrar todos los datos del periodo seleccionado", + "rewrite-latest-value": "Reescribir último valor" + } }, "api-usage": { "api-features": "Características API", @@ -757,6 +814,18 @@ "view-details": "Ver detalles", "view-statistics": "Ver estadísticas" }, + "api-limit": { + "cassandra-queries": "Consultas Cassandra", + "entity-version-creation": "Creación de versiones de entidad", + "entity-version-load": "Carga de versiones de entidad", + "notification-requests": "Solicitudes de notificación", + "notification-requests-per-rule": "Solicitudes de notificación por regla", + "rest-api-requests": "Solicitudes REST API", + "rest-api-requests-per-customer": "Solicitudes REST API por cliente", + "transport-messages": "Mensajes de transporte", + "transport-messages-per-device": "Mensajes de transporte por dispositivo", + "ws-updates-per-session": "Actualizaciones WS por sesión" + }, "audit-log": { "audit": "Auditoría", "audit-logs": "Registro Auditoría", @@ -808,7 +877,8 @@ "type-provision-success": "Dispositivo aprovisionado", "type-provision-failure": "Aprovisionamiento fallido", "type-timeseries-updated": "Telemetría actualizada", - "type-timeseries-deleted": "Telemetría borrada" + "type-timeseries-deleted": "Telemetría borrada", + "type-sms-sent": "SMS enviado" }, "confirm-on-exit": { "message": "Tienes cambios sin guardar. ¿Abandonar la página?", @@ -839,7 +909,9 @@ "created-time": "Fecha de creación", "loading": "Cargando...", "proceed": "Proceder", - "open-details-page": "Abrir detalles" + "open-details-page": "Abrir detalles", + "not-found": "No encontrado", + "documentation": "Documentación" }, "content-type": { "json": "Json", @@ -868,9 +940,9 @@ "manage-public-devices": "Gestionar dispositivos públicos", "manage-public-dashboards": "Gestionar paneles públicos", "manage-customer-assets": "Gestionar activos del cliente", + "manage-public-assets": "Gestionar activos públicos", "manage-customer-edges": "Administrar Edges de clientes", "manage-public-edges": "Administrar Edges públicos", - "manage-public-assets": "Gestionar activos públicos", "add-customer-text": "Agregar nuevo cliente", "no-customers-text": "No se encontraron clientes", "customer-details": "Detalles del cliente", @@ -902,6 +974,13 @@ "edges": "Instancias de Edge del cliente", "manage-edges": "Administrar Edges" }, + "date": { + "last-update-n-ago": "Última actualización hace N", + "last-update-n-ago-text": "Última actualización {{ agoText }}", + "custom-date": "Fecha personalizada", + "format": "Formato", + "preview": "Previsualizar" + }, "datetime": { "date-from": "Fecha desde", "time-from": "Hora desde", @@ -931,6 +1010,7 @@ "no-dashboards-text": "Ningún panel encontrado", "no-widgets": "Ningún widget configurado", "add-widget": "Agregar nuevo widget", + "add-widget-button-text": "Agregar widget", "title": "Título", "image": "Imagen de panel", "mobile-app-settings": "Ajustes de aplicación móvil", @@ -1059,6 +1139,7 @@ "public-link-copied-message": "El link público del panel se ha copiado al portapapeles", "manage-states": "Administrar estados de paneles", "states": "Estados de paneles", + "states-short": "Estados", "search-states": "Buscar estados de paneles", "selected-states": "{ count, plural, =1 {1 estado panel} other {# estado paneles} } seleccionados", "edit-state": "Editar estado panel", @@ -1087,11 +1168,14 @@ "unassign-dashboards-from-edge-text": "Después de la confirmación, se anulará la asignación de todos los paneles seleccionados y no serán accesibles por de Edge", "assign-dashboard-to-edge": "Asignar panel(es) al Edge", "assign-dashboard-to-edge-text": "Por favor selecciona los paneles para asignar al Edge", - "non-existent-dashboard-state-error": "El panel con id de estado \"{{ stateId }}\" no se ha encontrado" + "non-existent-dashboard-state-error": "El panel con id de estado \"{{ stateId }}\" no se ha encontrado", + "edit-mode": "Modo Edición" }, "datakey": { "settings": "Ajustes", + "general": "General", "advanced": "Avanzado", + "key": "Clave", "label": "Etiqueta", "color": "Color", "units": "Símbolo especial para mostrar junto con el valor", @@ -1111,6 +1195,10 @@ "function-types": "Tipos de funciones", "function-type": "Tipos de función", "function-types-required": "Tipos de funciones requerido.", + "data-keys": "Claves de datos", + "data-key": "Clave de datos", + "data-keys-required": "Se requieren claves de datos.", + "data-key-required": "Se requiere clave de datos.", "alarm-keys": "Claves de Alarmas", "alarm-key": "Clave de Slarma", "alarm-key-functions": "Funciones de claves de Alarmas", @@ -1143,7 +1231,13 @@ "delta-calculation-result": "Resultado de cálculo delta", "delta-calculation-result-previous-value": "Valor anterior", "delta-calculation-result-delta-absolute": "Delta (absoluto)", - "delta-calculation-result-delta-percent": "Delta (percentil)" + "delta-calculation-result-delta-percent": "Delta (percentil)", + "source": "Origen", + "latest": "Último", + "latest-value": "Último valor", + "delta": "delta", + "percent": "porcentaje", + "absolute": "absoluto" }, "datasource": { "type": "Típo de fuente de datos", @@ -1329,7 +1423,25 @@ "device-details": "Detalles del dispositivo" }, "unassign-devices-from-edge-title": "¿Está seguro de que desea desasignar {count, plural, =1 {1 dispositivo} other {# dispositivos} }?", - "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el Edge no podrá acceder a ellos." + "unassign-devices-from-edge-text": "Después de la confirmación, todos los dispositivos seleccionados quedarán sin asignar y el Edge no podrá acceder a ellos.", + "time": "Hora", + "connectivity": { + "check-connectivity": "Probar conectividad", + "device-created-check-connectivity": "Dispositivo creado. Prueba de conectividad.", + "loading-check-connectivity-command": "Cargando comandos...", + "use-following-instructions": "Usa las siguientes instrucciones para enviar telemetrías usando comandos shell", + "execute-following-command": "Ejecuta el comando siguietne", + "install-curl-windows": "Desde Windows 10 b17063, el comando cURL está disponible por defecto", + "install-curl-macos": "Desde Mac OS X 10.2 6C115 (Jaguar), el comando cURL está disponible por defecto", + "install-mqtt-windows": "Usa las instrucciones para descargar, instalar y configurar mosquitto_pub", + "install-coap-client": "Usa las instrucciones para descargar, instalar y configurar coap-client", + "install-necessary-client-tools": "Instala las herramientas de cliente", + "mqtts-x509-command": "Usa la documentación para conectar el dispositivo vía MQTT con autorización X509", + "coaps-x509-command": "Usa la documentación para conectar el dispositivo vía CoAP sobre DTLS con autorización X509", + "snmp-command": "Usa la siguiente documentación para conectar el dispositivo vía SNMP.", + "sparkplug-command": "Usa la siguiente documentación para conectar el dispositivo vía MQTT Sparkplug.", + "lwm2m-command": "Usa la siguiente documentación para conectar el dispositivo vía LWM2M." + } }, "asset-profile": { "asset-profile": "Perfil de activo", @@ -1411,6 +1523,7 @@ "transport-type-lwm2m-hint": "Transporte LWM2M", "transport-type-snmp": "SNMP", "transport-type-snmp-hint": "Configuración transporte SNMP", + "transport-type-http": "HTTP", "description": "Descripción", "default": "Defecto", "profile-configuration": "Configuración de perfil", @@ -1782,7 +1895,9 @@ } }, "dialog": { - "close": "Cerrar diálogo" + "close": "Cerrar diálogo", + "error-message-title": "Mensaje de error:", + "error-details-title": "Detalles de error" }, "direction": { "column": "Columna", @@ -1843,6 +1958,8 @@ "make-private-edge-text": "Después de la confirmación, el Edge y todos sus datos se harán privados y otros no podrán acceder a ellos", "import": "Importar Edge", "install-connect-instructions": "Instrucciones de instalación y conexión", + "install-connect-instructions-edge-created": "Edge creado! Revisa las instrucciones de instalación y conexión", + "loading-edge-instructions": "Cargando instrucciones edge...", "label": "Etiqueta", "load-entity-error": "Entidad no encontrada. No se pudo cargar la información", "assign-new-edge": "Asignar nuevo Edge", @@ -1853,11 +1970,11 @@ "edge-secret": "Secreto del Edge", "copy-edge-secret": "Copiar secreto del Edge", "edge-secret-copied-message": "El secreto de Edge se ha copiado al portapapeles", - "edge-assets": "Gestionar activos de Edges", - "edge-devices": "Gestionar dispositivos de Edge", - "edge-entity-views": "Gestionar vistas de entidad de Edge", - "edge-dashboards": "Administrar paneles de Edge", - "edge-rulechains": "Cadenas de reglas de Edge", + "manage-assets": "Gestionar activos", + "manage-devices": "Gestionar dispositivos", + "manage-entity-views": "Gestionar vistas de entidad", + "manage-dashboards": "Administrar paneles", + "manage-rulechains": "Administrar cadenas de reglas", "assets": "Activos de Edge", "devices": "Dispositivos de Edge", "entity-views": "Vistas de entidad de Edge", @@ -1894,11 +2011,15 @@ "type-rule-chain-metadata": "Metadatos de Cadena de Reglas", "type-edge": "Edge", "type-user": "Usuario", + "type-tenant": "Propietario", + "type-tenant-profile": "Perfil de Propietario", "type-customer": "Cliente", "type-relation": "Relación", "type-widgets-bundle": "Paquete de Widgets", "type-widgets-type": "Tipos de Widgets", "type-admin-settings": "Ajustes de Administración", + "type-ota-package": "Paquete OTA", + "type-queue": "Cola", "action-type-added": "Añadido", "action-type-deleted": "Borrado", "action-type-updated": "Actualizado", @@ -1914,6 +2035,8 @@ "action-type-rpc-call": "Llamada RPC", "action-type-alarm-ack": "ACK Alarma", "action-type-alarm-clear": "Borrado de Alarma", + "action-type-alarm-assigned": "Alarma Asignada", + "action-type-alarm-unassigned": "Alarma Desasignada", "action-type-assigned-to-edge": "Asignado a Edge", "action-type-unassigned-from-edge": "Desasignado de Edge", "action-type-credentials-request": "Obtención de Credenciales", @@ -1930,6 +2053,7 @@ "entities-count": "Nº de entidades", "alarms-count": "Nº de alarmas", "aliases": "Alias de entidad", + "aliases-short": "Alias", "entity-alias": "Alias de entidad", "unable-delete-entity-alias-title": "No ha sido posible eliminar el alias de entidad", "unable-delete-entity-alias-text": "El alias de entidad '{{entityAlias}}' no puede ser eliminado ya que se esta usando por los siguientes widgets:
{{widgetsList}}", @@ -1945,6 +2069,7 @@ "entity-types": "Tipos de entidades", "entity-type-list": "Lista de tipos de entidad", "any-entity": "Cualquier entdad", + "add-entity-type": "Añadir tipo de entidad", "enter-entity-type": "Introducir tipo de entidad", "no-entities-matching": "No se han encontrado entidades que coincidan con '{{entity}}' .", "no-entity-types-matching": "No se han encontrado tipos de entidad que coincidan con '{{entityType}}' .", @@ -1952,6 +2077,7 @@ "help-text": "Usar el símbolo '%' de acuerdo a las necesidades: '%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'.", "use-entity-name-filter": "Usar filtro", "entity-list-empty": "No hay entidades seleccionadas.", + "entity-type-list-required": "Al menos debe seleccionar un tipo de entidad", "entity-name-filter-required": "Filtro de nombre de entidad requerido.", "entity-name-filter-no-entity-matched": "No hay entidades que comiencen con '{{entity}}' .", "all-subtypes": "Todos", @@ -1959,6 +2085,7 @@ "no-aliases-found": "No se han encontrado alias.", "no-alias-matching": "'{{alias}}' no encontrado.", "create-new-alias": "Crear nuevo alias!", + "create-new": "Crear nuevo", "key": "Clave", "key-name": "Nombre de clave", "no-keys-found": "No se han encontrado claves.", @@ -1972,6 +2099,7 @@ "device-name-starts-with": "Dispositivos cuyos nombres comiencen por '{{prefix}}'", "type-device-profile": "Perfil de dispositivo", "type-device-profiles": "Perfiles de dispositivo", + "clear-selected-profiles": "Borrar perfiles seleccionados", "list-of-device-profiles": "{ count, plural, =1 {un perfil} other {Lista de # perfiles} }", "device-profile-name-starts-with": "Perfiles cuyo nombre empiece por '{{prefix}}'", "type-asset-profile": "Perfil de activo", @@ -2033,6 +2161,9 @@ "type-widgets-bundle": "Paquete de widgets", "type-widgets-bundles": "Paquetes de widgets", "list-of-widgets-bundles": "{ count, plural, =1 {Un paquete de widget} other {Lista de # paquetes de widgets} }", + "type-widget-type": "Tipo de widget", + "type-widget-types": "Tipos de widget", + "list-of-widget-types": "{ count, plural, =1 {Un tipo de widget} other {Lista de # tipos de widgets} }", "search": "Buscar entidades", "selected-entities": "{ count, plural, =1 {1 entidad} other {# entidades} } seleccionadas", "entity-label": "Etiqueta de entidad", @@ -2051,10 +2182,16 @@ "type-rpc": "RPC", "type-queue": "Cola", "type-notification": "Notificación", - "type-notification-rule": "Regla de notificaciones", - "type-notification-target": "Destinatario de notificaciones", + "type-notification-rule": "Regla de notificación", + "type-notification-rules": "Reglas de notificación", + "list-of-notification-rules": "{ count, plural, =1 {Una regla de notificación} other {Lista de # reglas de notificación} }", + "type-notification-target": "Destinatario de notificación", + "type-notification-targets": "Destinatarios de notificación", + "list-of-notification-targets": "{ count, plural, =1 {Un destinatario} other {Lista de # destinatarios} }", "type-notification-request": "Solicitud de notificaciones", - "type-notification-template": "Plantilla de notificaciones" + "type-notification-template": "Plantilla de notificaciones", + "type-notification-templates": "Plantillas de notificación", + "list-of-notification-templates": "{ count, plural, =1 {Una plantilla de notificación} other {Lista de # plantillas de notificación} }" }, "entity-field": { "created-time": "Hora de creación", @@ -2413,6 +2550,7 @@ "add-filter-prompt": "Por favos, añadir filtro", "no-filter-matching": "'{{filter}}' no encontrado.", "create-new-filter": "Crear un filtro nuevo!", + "create-new": "Crear nuevo", "filter-required": "Se requiere filtro.", "operation": { "operation": "Operación", @@ -2500,38 +2638,152 @@ }, "gateway": { "add-entry": "Añadir configuración", + "advanced": "Avanzado", + "checking-device-activity": "Probando actividad de dispositivo", + "command": "Comandos Docker", + "command-copied-message": "Se han copiado los comandos al portapapeles", + "configuration": "Configuración", "connector-add": "Añadir conector", "connector-enabled": "Activar conector", "connector-name": "Nombre conector", "connector-name-required": "Se requiere nombre conector.", "connector-type": "Tipo conector", "connector-type-required": "Se requiere tipo conector.", - "connectors": "Configuración de conectores", + "connectors": "Conectores", + "connectors-config": "Configuración de conectores", + "connectors-table-enabled": "Enabled", + "connectors-table-name": "Nombre", + "connectors-table-type": "Tipo", + "connectors-table-status": "Estado", + "connectors-table-actions": "Acciones", + "connectors-table-key": "Clave", + "connectors-table-class": "Clase", + "rpc-command-send": "Enviar", + "rpc-command-result": "Resultado", + "rpc-command-edit-params": "Editar parametros", + "gateway-configuration": "Configuración General", + "docker-label": "Usa los siguientes comandos para ejecutar el gateway en Docker.", "create-new-gateway": "Crear un gateway nuevo", "create-new-gateway-text": "Crear un nuevo gateway con el nombre: '{{gatewayName}}'?", + "created-time": "Hora de creación", + "configuration-delete-dialog-header": "Las configuraciones se borrarán", + "configuration-delete-dialog-body": "Sólo es posible desactivar la configuración remota, si hay acceso físico al gateway. Se borrarán todas las configuraciones previas.

\nPara desactivar la configuración, introduce el nombre del gateway aquí", + "configuration-delete-dialog-input": "Nombre Gateway", + "configuration-delete-dialog-input-required": "Se requiere nombre de gateway", + "configuration-delete-dialog-confirm": "Desactivar", "delete": "Borrar configuración", "download-tip": "Descargar fichero de configuración", + "drop-file": "Arrastra un fichero o", "gateway": "Gateway", "gateway-exists": "Ya existe un dispositivo con el mismo nombre.", "gateway-name": "Nombre de Gateway", "gateway-name-required": "Se requiere un nombre de gateway.", "gateway-saved": "Configuración de gateway grabada satisfactoriamente.", + "grpc": "GRPC", + "grpc-keep-alive-timeout": "Timeout Keep alive (en ms)", + "grpc-keep-alive-timeout-required": "Se requiere Timeout Keep alive", + "grpc-keep-alive-timeout-min": "El valor no puede ser menor de 1", + "grpc-keep-alive-timeout-pattern": "El valor no es válido", + "grpc-keep-alive": "Keep alive (en ms)", + "grpc-keep-alive-required": "Se requiere keep alive", + "grpc-keep-alive-min": "El valor no puede ser menor de 1", + "grpc-keep-alive-pattern": "El valor keep alive no es válido", + "grpc-min-time-between-pings": "Tiempo mínimo entre pings (en ms)", + "grpc-min-time-between-pings-required": "Se requiere tiempo mínimo entre pings", + "grpc-min-time-between-pings-min": "El valor no puede ser menor de 1", + "grpc-min-time-between-pings-pattern": "El valor de tiempo mínimo entre pings no es válido", + "grpc-min-ping-interval-without-data": "Intervalo mínimo sin datos (en ms)", + "grpc-min-ping-interval-without-data-required": "Se requiere intervalo", + "grpc-min-ping-interval-without-data-min": "El valor no puede ser menor de 1", + "grpc-min-ping-interval-without-data-pattern": "El valor de intervalo no es válido", + "grpc-max-pings-without-data": "Intervalo máximo sin datos", + "grpc-max-pings-without-data-required": "Se requiere intervalo", + "grpc-max-pings-without-data-min": "El valor no puede ser menor de 1", + "grpc-max-pings-without-data-pattern": "El valor de intervalo no es válido", + "inactivity-check-period-seconds": "Periodo de control de inactividad (en segundos)", + "inactivity-check-period-seconds-required": "Se requiere periodo", + "inactivity-check-period-seconds-min": "El valor no puede ser menor de 1", + "inactivity-check-period-seconds-pattern": "El valor del periodo no es válido", + "inactivity-timeout-seconds": "Timeout de inactividad (en segundos)", + "inactivity-timeout-seconds-required": "Se requiere timeout de inactividad", + "inactivity-timeout-seconds-min": "El valor no puede ser menor de 1", + "inactivity-timeout-seconds-pattern": "El valor de inactividad no es válido", "json-parse": "JSON no válido.", "json-required": "El campo no puede estar vacío.", + "logs": { + "logs": "Registros", + "days": "días", + "hours": "horas", + "minutes": "minutos", + "seconds": "segundos", + "date-format": "Formato de fecha", + "date-format-required": "Se requiere formato de fecha", + "log-format": "Formato de registro", + "log-type": "Tipo de registro", + "log-format-required": "Se requiere tipo de registro", + "remote": "Registro remoto", + "remote-logs": "Registro remoto", + "local": "Registro local", + "level": "Nivel de registro", + "file-path": "Ruta de fichero", + "file-path-required": "Se requiere ruta de fichero", + "saving-period": "Periodo de guardado de registros", + "saving-period-min": "El periodo no puede ser menor que 1", + "saving-period-required": "Se requiere periodo de guardado", + "backup-count": "Número de backups", + "backup-count-min": "El número de backups no puede ser menor que 1", + "backup-count-required": "Se requiere número de backups" + }, + "min-pack-send-delay": "Tiempo de espera, envío de paquetes (en ms)", + "min-pack-send-delay-required": "Se requiere tiempo de espera", + "min-pack-send-delay-min": "El tiempo de espera no puede ser menor que 0", "no-connectors": "No hay conectores", "no-data": "No hay configuraciones", "no-gateway-found": "No se ha encontrado ningún gateway.", "no-gateway-matching": " '{{item}}' no encontrado.", "path-logs": "Ruta a los archivos de log", "path-logs-required": "Ruta requerida.", + "permit-without-calls": "Permitir Keep alive si llamadas", "remote": "Configuración remota", "remote-logging-level": "Nivel de logging", "remove-entry": "Borrar configuración", + "remote-shell": "Consola remota", + "remote-configuration": "Configuración remota", + "other": "otros", "save-tip": "Grabar fichero de configuración", "security-type": "Tipo de seguridad", "security-types": { - "access-token": "Token de acceso", - "tls": "TLS" + "access-token": "Tóken de acceso", + "username-password": "Usuario y contraseña", + "tls": "TLS", + "tls-access-token": "TLS + Tóken de acceso", + "tls-private-key": "TLS + Clave privada" + }, + "server-port": "Puerto del servidor", + "statistics": { + "statistic": "Estadística", + "statistics": "Estadísticas", + "statistic-commands-empty": "No hay estadísticas", + "commands": "Comandos", + "send-period": "Periodo de envío de estadísticas (en segundos)", + "send-period-required": "Se requiere periodo de envío", + "send-period-min": "El periodo de envío no puede ser menor de 60", + "send-period-pattern": "El periodo de envío no es válido", + "check-connectors-configuration": "Revisar configuración de conectores (en segundos)", + "check-connectors-configuration-required": "Se requiere un valor", + "check-connectors-configuration-min": "El valor no puede ser menor de 1", + "check-connectors-configuration-pattern": "La configuración no es válida", + "add": "Añadir comando", + "timeout": "Timeout", + "timeout-ms": "Timeout (en ms)", + "timeout-required": "Se requiere timeout", + "timeout-min": "El timeout no puede ser menor de 1", + "timeout-pattern": "El timeout no es válido", + "attribute-name": "Nombre de atributo", + "attribute-name-required": "Se requiere nombre de atributo", + "command": "Comando", + "command-required": "Se requiere comando", + "remove": "Borrar comando" }, "storage": "Grabación", "storage-max-file-records": "Número máximo de registros en fichero", @@ -2543,6 +2795,16 @@ "storage-max-records-min": "El número mínimo es 1.", "storage-max-records-pattern": "Número no válido.", "storage-max-records-required": "Se requiere número.", + "storage-read-record-count": "Leer número de entradas en almacén", + "storage-read-record-count-min": "El número mínimo de entradas es 1.", + "storage-read-record-count-pattern": "El número no es válido.", + "storage-read-record-count-required": "Se requiere número de entradas.", + "storage-max-read-record-count": "Número máximo de entradas en el almacén", + "storage-max-read-record-count-min": "El número mínimo es 1.", + "storage-max-read-record-count-pattern": "El número no es válido", + "storage-max-read-record-count-required": "Se requiere número máximo de entradas.", + "storage-data-folder-path": "Ruta de carpeta de datos", + "storage-data-folder-path-required": "Se requiere ruta.", "storage-pack-size": "Tamaño máximo de eventos", "storage-pack-size-min": "El número mínimo es 1.", "storage-pack-size-pattern": "Número no válido.", @@ -2551,10 +2813,12 @@ "storage-path-required": "Se requiere ruta de almacén.", "storage-type": "Tipo de almacén", "storage-types": { - "file-storage": "Almacén fichero", - "memory-storage": "Almacén en memoria" + "file-storage": "Almacén en fichero", + "memory-storage": "Almacén en memoria", + "sqlite": "SQLITE" }, "thingsboard": "ThingsBoard", + "general": "General", "thingsboard-host": "Host ThingsBoard", "thingsboard-host-required": "Se requiere Host.", "thingsboard-port": "Puerto ThingsBoard", @@ -2567,10 +2831,61 @@ "title-connectors-json": "Configuración conector {{typeName}}", "tls-path-ca-certificate": "Ruta al certificado CA en el gateway", "tls-path-client-certificate": "Ruta al certificado cliente en el gateway", + "messages-ttl-check-in-hours": "Comprobación de TTL de mensajes en horas", + "messages-ttl-check-in-hours-required": "Campo requerido.", + "messages-ttl-check-in-hours-min": "El mínimo es 1.", + "messages-ttl-check-in-hours-pattern": "El número no es válido.", + "messages-ttl-in-days": "TTL (Time to live) de mensages en días", + "messages-ttl-in-days-required": "Se requiere TTL de mensajes.", + "messages-ttl-in-days-min": "El número mínimo es 1.", + "messages-ttl-in-days-pattern": "El número no es válido.", + "mqtt-qos": "QoS", + "mqtt-qos-required": "Se requiere QoS", + "mqtt-qos-range": "El rango de valores es desde 0 a 1", "tls-path-private-key": "Ruta a la clave privada en el gateway", "toggle-fullscreen": "Pantalla completa fullscreen", "transformer-json-config": "Configuración JSON*", - "update-config": "Añadir/actualizar configuración JSON" + "update-config": "Añadir/actualizar configuración JSON", + "hints": { + "remote-configuration": "Habilita la administración y configuración remota del gateway", + "remote-shell": "Habilita el control remoto del sistema operativo del gateway desde el widget terminal remoto", + "host": "Hostname o dirección IP del servidor Thingsboard", + "port": "Puerto del servicio MQTT en el servidor Thingsboard", + "token": "Access token para el gateway", + "client-id": "ID de cliente MQTT para el gateway", + "username": "Usuario MQTT para el gateway", + "password": "Contraseña MQTT para el gateway", + "ca-cert": "Ruta al fichero del certificado CA", + "date-form": "Formato de fecha en los mensajes de registro", + "data-folder": "Ruta a la carpeta que contendrá los datos (Relativa o absoluta)", + "log-format": "Formato de mensajes en registro", + "remote-log": "Habilita el registro remoto y la posterior lectura desde el gateway", + "backup-count": "Si el contaje de copias de seguridad es mayor que 0, cuando se realice una renovación, no se conservan más que los archivos de recuento de copias de seguridad, los más antíguos se eliminarán", + "storage": "Provee la configuración para el grabado de datos entrantes antes de que se envíen a la plataforma", + "max-file-count": "Número máximo de ficheros que se crearán", + "max-read-count": "Númeo máximo de mensajes a obtener desde el disco y enviados a la plataforma", + "max-records": "Número máximo de registros que se guardarán en un solo fichero", + "read-record-count": "Número de mensages a obtener desde el almacenamiento y enviados a la plataforma", + "max-records-count": "Número máximo de datos en almacenamiento antes de enviar a la plataforma", + "ttl-check-hour": "Con qué frecuencia el gateway comprobará si los datos están obsoletos", + "ttl-messages-day": "Número máximo de días para la retención de datos en el almacén", + "commands": "Comandos para recoger estadísticas adicionales", + "attribute": "Clave de telemetría para estadísticas", + "timeout": "Timeout para la ejecución de comandos", + "command": "El resultado de la ejecución del comando, se usará como valor para la telemetría", + "check-device-activity": "Habilita la monitorización de cada uno de los dispositivos conectados", + "inactivity-timeout": "Tiempo tras que el gateway desconectará el dispositivo", + "inactivity-period": "Periodo de monitorización de actividad en el dispositivo", + "minimal-pack-delay": "Tiempo de espera entre envío de paquetes de mensajes (Un valor muy bajo, resultará en un aumento de uso de la CPU en el gateway)", + "qos": "Quality of Service en los mensajes MQTT (0 - at most once, 1 - at least once)", + "server-port": "Puerto de red en el cual el servidor GRPC escuchará conexiones entrantes.", + "grpc-keep-alive-timeout": "Tiempo máximo, el cual el servidor esperara un ping keepalive antes de considerar la conexión terminada.", + "grpc-keep-alive": "Duración entre dos pings keepalive cuando no haya llamada RPC activa.", + "grpc-min-time-between-pings": "Mínimo tiempo que el servidor debe esperar entre envíos de mensajes de ping", + "grpc-max-pings-without-data": "Número máximo de pings keepalive que el servidor puede enviar sin recibir ningún dato antes de considerar la conexión terminada.", + "grpc-min-ping-interval-without-data": "Mínimo tiempo que el servidor debe esperar entre envíos de ping keepalive cuando no haya ningún dato en envío o recepción.", + "permit-without-calls": "Permitir al servidor mantener la conexión GRPC abierta, cuando no haya llamadas RPC activas." + } }, "grid": { "delete-item-title": "¿Quieres eliminar este item?", @@ -2603,6 +2918,9 @@ }, "image-input": { "drop-images-or": "Arrastrar y soltar imagenes o", + "drag-and-drop": "Arrastrar y soltar", + "or": "O", + "browse": "Navegar", "no-images": "No hay imágenes seleccionadas", "images": "imágenes" }, @@ -2653,6 +2971,12 @@ "lwm2m-server-secret-key": "Clave secreta servidor LwM2M", "lwm2m-server-public-key-id": "Clave pública servidor LwM2M" }, + "snmp": { + "host": "Host SNMP", + "port": "Puerto SNMP", + "version": "Versión SNMP (v1, v2c or v3)", + "community-string": "String de SNMP community" + }, "isgateway": "Es Gateway", "activity-time-from-gateway-device": "Fecha de actividad desde el dispositivo gateway", "description": "Descripción", @@ -2689,6 +3013,7 @@ }, "layout": { "layout": "Diseño", + "layouts": "Diseños", "manage": "Administrar diseños", "settings": "Ajustes de diseño", "color": "Color", @@ -2714,6 +3039,12 @@ "legend": { "direction": "Dirección de la leyenda", "position": "Posición de la leyenda", + "show-values": "Mostrar valores", + "min-option": "Min", + "max-option": "Max", + "average-option": "Media", + "total-option": "Total", + "latest-option": "Últimos", "sort-legend": "Ordenar claves en leyenda", "show-max": "Mostrar valor máximo", "show-min": "Mostrar valor mínimo", @@ -2795,6 +3126,7 @@ "api-feature-hint": "Si el campo está vacío, la activación se aplicará a todas las características API", "api-usage-trigger-settings": "Ajustes de activación de uso API", "new-platform-version-trigger-settings": "Ajustes de activación de nueva versión de plataforma", + "rate-limits-trigger-settings": "Ajustes de límites excedidos", "at-least-one-should-be-selected": "Se debe seleccionar por lo menos uno", "basic-settings": "Ajustes básicos", "button-text": "Texto del botón", @@ -2835,6 +3167,8 @@ "email-preview": "Vista previa de notificación eMail", "slack": "Slack", "slack-preview": "Vista previa de notificación Slack", + "microsoft-teams": "Microsoft Teams", + "microsoft-teams-preview": "Vista previa de notificación por Microsoft Teams", "sms": "SMS", "sms-preview": "Vista previa de notificación SMS", "web": "Web", @@ -2872,6 +3206,7 @@ "dashboard": "Abrir panel", "link": "Abrir enlace URL" }, + "loading-notifications": "Cargando notificaciones...", "management": "Administración de notificaciones", "mark-all-as-read": "Marcar todas como leídas", "mark-as-read": "Marcar como leída", @@ -2912,6 +3247,8 @@ "only-rule-chain-lifecycle-failures": "Sólo fallos de ciclo de vida en cadena de reglas", "only-rule-node-lifecycle-failures": "Sólo fallos de ciclo de vida en nodos de reglas", "platform-users": "Usuarios de la plataforma", + "rate-limits": "Límites de tasa", + "rate-limits-hint": "Si el campo está vacío, el activador se aplicará a todos los límites de tasa", "recipient": "Destinatario", "recipient-group": "Grupo de destinatarios", "recipient-type": { @@ -2945,6 +3282,8 @@ "rule-engine-filter": "Filtro de motor de reglas", "rule-name": "Nombre de regla", "rule-name-required": "Se requiere nombre", + "rule-disable": "Desactivar regla de notificación", + "rule-enable": "Activar regla de notificación", "rule-node-filter": "Filtro de regla", "rules": "Reglas", "notification-rules": "Notificaciones / Reglas", @@ -2988,13 +3327,15 @@ "general": "General", "rule-engine-lifecycle-event": "Evento de ciclo de vida en motor de reglas", "rule-node": "Nodo de regla", - "new-platform-version": "Nueva versión de plataforma" + "new-platform-version": "Nueva versión de plataforma", + "rate-limits": "Se excedieron los límites de tasa" }, "templates": "Plantillas", "notification-templates": "Notificaciones / Plantillas", "tenant-profiles-list-rule-hint": "Si el campo está vacío, el disparo se aplicará a todos los perfiles de administradores propietarios", "tenants-list-rule-hint": "Si el campo está vacío, el disparo se aplicará a todos los administradores propietarios", "threshold": "Umbral", + "theme-color": "Color del tema", "time": "Hora", "track-rule-node-events": "Hacer seguimiento de eventos en nodos de reglas", "trigger": { @@ -3007,6 +3348,7 @@ "entity-action": "Actiones de entidades", "rule-engine-lifecycle-event": "Evento de ciclo de vida en Motor de reglas", "new-platform-version": "Nueva versión de plataforma", + "rate-limits": "Se excedieron los límites de tasa", "trigger": "Disparo", "trigger-required": "Se requiere disparo" }, @@ -3015,7 +3357,21 @@ "updated": "Actualizado", "use-template": "Usar plantilla", "view-all": "Ver todos", - "warning": "Alerta" + "warning": "Alerta", + "webhook-url": "URL Webhook", + "webhook-url-required": "Se requiere URL Webhook", + "channel-name": "Nombre del canal", + "channel-name-required": "Se requiere nombre del canal", + "settings": { + "notification-settings": "Ajustes de notificaciones", + "reset-all": "Restablecer ajustes", + "reset-all-title": "Estás seguro de borrar el formulario?", + "reset-all-text": "Atención, tras la confirmación, el formulario de ajustes se restablecerá a los valores por defecto.", + "type": "Tipo", + "enable-all": "Activar todos", + "disable-all": "Desactivar todos", + "delivery-not-configured": "No hay configurado un método de entrega" + } }, "ota-update": { "add": "Añadir paquete", @@ -3104,7 +3460,14 @@ }, "security": { "security": "Seguridad", - "general-settings": "Ajusters generales de seguridad", + "general-settings": "Ajustes generales de seguridad", + "access-token": "Tóken de acceso", + "access-token-required": "Tóken de acceso requerido.", + "clientId": "ID cliente", + "clientId-required": "Se requiere ID cliente", + "username": "Usuario", + "username-required": "Se requiere usuario", + "ca-cert": "Certificado CA", "2fa": { "2fa": "Autenticación de doble factor (2FA)", "2fa-description": "La autenticación de doble factor proteje tu cuenta de accesos no autorizados. Lo único que tienes que hacer es entrar un código de seguridad al hacer login.", @@ -3177,6 +3540,7 @@ "relation": { "relations": "Relaciones", "direction": "Dirección", + "clear-relation-type": "Borrar tipo de relación", "search-direction": { "FROM": "Desde", "TO": "Hacia" @@ -3210,7 +3574,8 @@ "delete-from-relation-text": "Atención, tras la confirmación la entidad actual no estará relacionada con la entidad '{{entityName}}'.", "delete-from-relations-title": "¿Quieres eliminar { count, plural, =1 {1 relación} other {# relaciones} }?", "delete-from-relations-text": "Atención, tras la confirmación todas las relaciones seleccionadas se eliminarán y sus entidades correspondientes no estarán relacionadas con sus entidades correspondientes.", - "remove-relation-filter": "Quitar filtro de relación", + "remove-relation-filter": "Borrar filtro de relación", + "remove-filter": "Borrar filtro", "add-relation-filter": "Añadir filtro de relación", "any-relation": "Cualquier relación", "relation-filters": "Filtro de relación", @@ -3220,6 +3585,7 @@ }, "resource": { "add": "Añadir Recurso", + "all-types": "Todos", "copyId": "Copiar Id de recurso", "delete": "Borrar recurso", "delete-resource-text": "Atención, tras la confirmación el recurso será irrecuperable.", @@ -3245,7 +3611,13 @@ "system": "Sistema", "title": "Título", "title-required": "Título requerido.", - "title-max-length": "El título debe ser menor de 256" + "title-max-length": "El título debe ser menor de 256", + "type": { + "jks": "JKS", + "js-module": "Módulo JS", + "lwm2m-model": "Modelo LWM2M", + "pkcs-12": "PKCS #12" + } }, "rulechain": { "rulechain": "Cadena de Regla", @@ -3316,11 +3688,13 @@ "events": "Eventos", "search": "Buscar nodos", "open-node-library": "Abrir librería de nodos", + "close-node-library": "Cerrar librería de nodos", "add": "Añadir nodo de reglas", "name": "Nombre", "name-required": "El nombre es requerido.", "name-max-length": "Nombre debe ser menor de 256", "type": "Tipo", + "rule-node-description": "Descripción de nodo de reglas", "delete": "Eliminar nodo de reglas", "select-all-objects": "Seleccionar todos los nodos y conexiones", "deselect-all-objects": "Deshacer selección de todos los nodos y conexiones", @@ -3379,7 +3753,8 @@ "output": "Salida", "test": "Test", "help": "Ayuda", - "reset-debug-mode": "Restablecer el modo de depuración en todos los nodos" + "reset-debug-mode": "Restablecer el modo de depuración en todos los nodos", + "test-with-this-message": "{{test}} con este mensaje" }, "timezone": { "timezone": "Zona Horaria", @@ -3392,7 +3767,7 @@ "queue-name": "Cola", "no-queues-found": "No se encontraron colas.", "no-queues-matching": "No se encontraron colas que coincidan con '{{queue}}'.", - "select_name": "Selecciona el nombre de la cola", + "select-name": "Selecciona el nombre de la cola", "name": "Nombre Cola", "name-required": "Necesario especificar el nombre de cola", "name-unique": "El nombre de cola ya existe!", @@ -3453,6 +3828,8 @@ "description": "Descripción", "description-hint": "Este texto se mostrará en la descripción de la cola, en lugar de la estrategia seleccionada", "alt-description": "Estrategia de envío: {{submitStrategy}}, Estrategia de procesamiento: {{processingStrategy}}", + "custom-properties": "Propiedades personalizadas", + "custom-properties-hint": "Propiedades de creación de tema en colas personalizadas, p.e. 'retention.ms:604800000;retention.bytes:1048576000'", "strategies": { "sequential-by-originator-label": "Secuencial por iniciador", "sequential-by-originator-hint": "El nuevo mensaje por ejemplo dispositivo A, no se enviará hasta que el mensaje anterior del dispositivo A sea admitido/procesado", @@ -3632,6 +4009,7 @@ "max-emails": "Nº Máximo de emails (0 - sin límite)", "max-emails-required": "Nº Máximo de emails requerido.", "max-emails-range": "Nº Máximo de emails no puede ser negativo", + "sms-enabled": "SMS Activados", "max-sms": "Nº Máximo de mensajes SMS (0 - sin límite)", "max-sms-required": "Nº Máximo de mensajes SMS requerido.", "max-sms-range": "Nº Máximo de mensajes SMS no puede ser negativo", @@ -3742,16 +4120,24 @@ "days": "Días" }, "timewindow": { + "timewindow": "Ventana de tiempo", "years": "{ years, plural, =1 { año } other {# años } }", + "years-short": "{{ years }}a", "months": "{ months, plural, =1 { mes } other {# meses } }", + "months-short": "{{ months }}M", "weeks": "{ weeks, plural, =1 { semana } other {# semanas } }", + "weeks-short": "{{ weeks }}sem", "days": "{ days, plural, =1 { día } other {# días } }", + "days-short": "{{ days }}d", "hours": "{ hours, plural, =0 { horas } =1 {1 hora } other {# horas } }", "hr": "{{ hr }} hr", + "hr-short": "{{ hr }}h", "minutes": "{ minutes, plural, =0 { minutos } =1 {1 minuto } other {# minutos } }", "min": "{{ min }} min", + "min-short": "{{ min }}m", "seconds": "{ seconds, plural, =0 { segundos } =1 {1 segundo } other {# segundos } }", "sec": "{{ sec }} sec", + "sec-short": "{{ sec }}s", "short": { "days": "{ days, plural, =1 {1 día } other {# días } }", "hours": "{ hours, plural, =1 {1 hora } other {# horas } }", @@ -3770,7 +4156,436 @@ "hide": "Ocultar", "interval": "Intervalo", "just-now": "Ahora mismo", - "ago": "hace" + "just-now-lower": "ahora mismo", + "ago": "hace", + "style": "Estilo de ventana de tiempo", + "icon": "Icono", + "icon-position": "Posición de icono", + "icon-position-left": "Izquierda", + "icon-position-right": "Derecha", + "font": "Fuente", + "color": "Color", + "displayTypePrefix": "Mostrar prefijo en tiempo real/histórico", + "preview": "Previsualizar" + }, + "unit": { + "millimeter": "Milímetro", + "centimeter": "Centímetro", + "angstrom": "Angstrom", + "nanometer": "Nanómetro", + "micrometer": "Micrómetro", + "meter": "Metro", + "kilometer": "Kilómetro", + "inch": "Pulgada", + "foot": "Pie", + "yard": "Yarda", + "mile": "Milla", + "nautical-mile": "Milla Náutica", + "astronomical-unit": "Unidad Astronómica", + "reciprocal-metre": "Metro recíproco", + "meter-per-meter": "Metro por metro", + "steradian": "Estereorradián", + "thou": "Tú", + "barleycorn": "Grano de cebada", + "hand": "Hand", + "chain": "Cadena", + "furlong": "Furlong", + "league": "League", + "fathom": "Fathom", + "cable": "Cable", + "link": "Enlace", + "rod": "Barra", + "nanogram": "Nanogramo", + "microgram": "Microgramo", + "milligram": "Miligramo", + "gram": "Gramo", + "kilogram": "Kilogramo", + "tonne": "Tonelada", + "ounce": "Onza", + "pound": "Libra", + "stone": "Piedra", + "hundredweight-count": "Hundredweight", + "short-tons": "Tonelada corta", + "dalton": "Dalton", + "grain": "Grano", + "drachm": "Dracma", + "quarter": "Cuarto", + "slug": "Lingote", + "carat": "Quilate", + "cubic-millimeter": "Milímetro Cúbico", + "cubic-centimeter": "Centímetro Cúbico", + "cubic-meter": "Metro Cúbico/s", + "cubic-kilometer": "Kilómetro Cúbico", + "microliter": "Microlitro", + "milliliter": "Mililitro", + "liter": "Litro", + "hectoliter": "Hectolitro", + "cubic-inch": "Pulgada Cúbica", + "cubic-foot": "Pié Cúbico", + "cubic-yard": "Yarda Cúbica", + "fluid-ounce": "Onza Fluida", + "pint": "Pinta", + "quart": "Cuarta", + "gallon": "Galón", + "oil-barrels": "Barriles de Aceite", + "cubic-meter-per-kilogram": "Metro Cúbico por Kilogramo", + "gill": "Cuarta parte de una pinta", + "hogshead": "Tonel", + "teaspoon": "Cucharilla", + "tablespoon": "Cucharada", + "cup": "Taza", + "celsius": "Celsius", + "kelvin": "Kelvin", + "rankine": "Rankine", + "fahrenheit": "Fahrenheit", + "percent": "%", + "meter-per-second": "Metros por Segundo", + "kilometer-per-hour": "Kilómetros por Hora", + "foot-per-second": "Pies por Segundo", + "mile-per-hour": "Millas por Hora", + "knot": "Nudo", + "millimeters-per-minute": "Milímetros por minuto", + "kilometer-per-hour-squared": "Kilómetros al cuadrado por hora", + "foot-per-second-squared": "Pie al cuadrado por segundo", + "pascal": "Pascal", + "kilopascal": "Kilopascale", + "megapascal": "Megapascal", + "gigapascal": "Gigapascal", + "millibar": "Milibar", + "bar": "Bar", + "kilobar": "Kilobar", + "newton": "Newton", + "newton-meter": "Newton metro", + "foot-pounds": "Libras-pie", + "inch-pounds": "Pulgadas-pie", + "newton-per-meter": "Newton por metro", + "atmospheres": "Atmósferas", + "pounds-per-square-inch": "Libras por pulgada cuadrada", + "torr": "Torr", + "inches-of-mercury": "Pulgadas de mercurio", + "pascal-per-square-meter": "Pascales por metro cuadrado", + "pound-per-square-inch": "Pie por pulgada cuadrada", + "newton-per-square-meter": "Newtons por metro cuadrado", + "kilogram-force-per-square-meter": "Kilogramo de fuerza por metro cuadrado", + "pascal-per-square-centimeter": "Pascales por centímetro cuadrado", + "ton-force-per-square-inch": "Tonelada de fuerza por pulgada cuadrada", + "kilonewton-per-square-meter": "Kilonewtons por metro cuadrado", + "newton-per-square-millimeter": "Newton por milímetro cuadrado", + + "microjoule": "Microjulio", + "millijoule": "Milijulio", + "joule": "Julio", + "kilojoule": "Kilojulio", + "megajoule": "Megajulio", + "gigajoule": "Gigajulio", + "watt-hour": "Watios-hora", + "kilowatt-hour": "Kilowatios-hora", + "electron-volts": "Electronvoltios", + "joules-per-coulomb": "Julios por Coulomb", + "british-thermal-unit": "British Thermal Units (BTU)", + "foot-pound": "Foot-pound", + "calorie": "Caloría", + "small-calorie": "Caloría-pequeña", + "kilocalorie": "Kilocaloría", + "joule-per-kelvin": "Julios por Kelvin", + "joule-per-kilogram-kelvin": "Julio por Kilogramo-Kelvin", + "joule-per-kilogram": "Julio por Kilogramo", + "watt-per-meter-kelvin": "Watios por metro Kelvin", + "joule-per-cubic-meter": "Julios por metro cúbico", + "therm": "Termia", + "electric-dipole-moment": "Momento dipolar eléctrico", + "magnetic-dipole-moment": "Momento dipolar magnético", + "debye": "Debyé", + "coulomb-per-square-meter-per-volt": "Culombio por metro cuadrado por Voltio", + "milliwatt": "Miliwatio", + "microwatt": "Microwatio", + "watt": "Watio", + "kilowatt": "Kilowatio", + "megawatt": "Megawatio", + "gigawatt": "Gigawatio", + "metric-horsepower": "Caballos métricos", + "milliwatt-per-square-centimeter": "Miliwatios por centímetro cuadrado", + "watt-per-square-centimeter": "Watios por centímetro cuadrado", + "kilowatt-per-square-centimeter": "Kilowatios por centímetro cuadrado", + "milliwatt-per-square-meter": "Miliwatios por metro cuadrado", + "watt-per-square-meter": "Watios por metro cuadrado", + "kilowatt-per-square-meter": "Kilowatios por metro cuadrado", + "watt-per-square-inch": "Watios por pulgada cuadrada", + "kilowatt-per-square-inch": "Kilowatios por pulgada cuadrada", + "horsepower": "Caballos", + "btu-per-hour": "BTU/h", + "coulomb": "Culombio", + "millicoulomb": "Miliculombios", + "microcoulomb": "Microculombios", + "picocoulomb": "Picoculombios", + "coulomb-per-meter": "Culombio por metro", + "coulomb-per-cubic-meter": "Culombio por metro cúbico", + "coulomb-per-square-meter": "Culombio por metro cuadrado", + "square-millimeter": "Milímetro cuadrado", + "square-centimeter": "Centímetro cuadrado", + "square-meter": "Metro Cuadrado", + "hectare": "Hectárea", + "square-kilometer": "Kilómetro Cuadrado", + "square-inch": "Pulgada Cuadrada", + "square-foot": "Pie Cuadrada", + "square-yard": "Yarda Cuadrada", + "acre": "Hectárea", + "square-mile": "Milla Cuadrada", + "are": "Área", + "barn": "Barnio", + "circular-inch": "Pulgada circular", + "milliampere-hour": "Miliamperios hora", + "milliampere-hour-tags": "intensidad eléctrica, flujo de corriente, carga eléctrica, capacidad actual, flujo de electricidad, flujo eléctrico, miliamperio hora, miliamperios hora, mAh", + "ampere-hours": "Amperios hora", + "ampere-hours-tags": "intensidad eléctrica, flujo de corriente, carga eléctrica, capacidad actual, flujo de electricidad, flujo eléctrico, ampere, amperio hora, Ah", + "kiloampere-hours": "Kiloamperios hora", + "kiloampere-hours-tags": "intensidad eléctrica, flujo de corriente, carga eléctrica, capacidad actual, flujo de electricidad, flujo eléctrico, kiloamperio hora, kiloampreios hora, kAh", + "nanoampere": "Nanoamperio", + "nanoampere-tags": "intensidad, amperios, nanoamperio, nA", + "picoampere": "Picoamperio", + "picoampere-tags": "intensidad, amperios, picoamperio, pA", + "microampere": "Microamperio", + "microampere-tags": "intensidad eléctrica, microamperio, microamperios, μA", + "milliampere": "Miliamperio", + "milliampere-tags": "intensidad eléctrica, miliamperio, miliamperios, mA", + "ampere": "Amperio", + "ampere-tags": "intensidad eléctrica, flujo de corriente, flujo de electricidad, flujo eléctrico, amperio, amperios, amperaje, A", + "kiloamperes": "Kiloamperios", + "kiloamperes-tags": "intensidad eléctrica, flujo de corriente, kiloamperios, kA", + "microampere-per-square-centimeter": "Microamperio por centímetro cuadrado", + "microampere-per-square-centimeter-tags": "Densidad de intensidad, microamperio por centímetro cuadrado, µA/cm²", + "ampere-per-square-meter": "Amperio por metro cuadrado", + "ampere-per-square-meter-tags": "Densidad de intensidad, intensidad por área de unidad, amperio por metro cuadrado, A/m²", + "ampere-per-meter": "Amperio por Metro", + "ampere-per-meter-tags": "fuerza del campo magnético, intensidad del campo magnético, amperios por metro, A/m", + "oersted": "Oersted", + "oersted-tags": "campo magnético, oersted, Oe", + "bohr-magneton": "Magneton de Bohr", + "bohr-magneton-tags": "física atómica, momento magnético, magnetón de bohr, μB", + "ampere-meter-squared": "Amperios metro al cuadrado", + "ampere-meter-squared-tags": "momento magnético, momento dipolar, ampero metro cuadrado, A·m²", + "ampere-meter": "Amperio Metro", + "ampere-meter-tags": "campo magnético, bucle de corriente, ampero metro, A·m", + "nanovolt": "Nanovoltio", + "picovolt": "Picovoltio", + "millivolts": "Milivoltios", + "microvolts": "Microvoltios", + "volt": "Voltio", + "kilovolts": "Kilovoltios", + "dbmV": "dBmV", + "volt-meter": "Voltio-Metro", + "kilovolt-meter": "Kilovoltio-Metro", + "megavolt-meter": "Megavoltio-Metro", + "microvolt-meter": "Microvoltio-Metro", + "millivolt-meter": "Milivoltio-Metro", + "nanovolt-meter": "Nanovoltio-Metro", + "ohm": "Ohmio", + "microohm": "Microohmio", + "milliohm": "Miliohmio", + "kilohm": "Kiloohmio", + "megohm": "Megaohmio", + "gigohm": "Gigaohmio", + "hertz": "Hertzio", + "kilohertz": "Kilohertzio", + "megahertz": "Megahertzio", + "gigahertz": "Gigahertzio", + "rpm": "Revoluciones por minuto", + "candela-per-square-meter": "Candela por metro cuadrado", + "candela": "Candela", + "lumen": "Lúmenes", + "lux": "Lux", + "foot-candle": "Candela", + "lumen-per-square-meter": "Lúmenes por metro cuadrado", + "lux-second": "Lux segundo", + "lumen-second": "Lumen segundo", + "lumens-per-watt": "Lumens por watio", + "absorbance": "Absorbancia", + "mole": "Mole", + "nanomole": "Nanomole", + "micromole": "MicroMole", + "millimole": "Milimole", + "kilomole": "Kilomole", + "mole-per-cubic-meter": "Mole por metro cúbico", + "rssi": "RSSI", + "ppm": "Partes Por Millón", + "ppb": "Partes Por Billión", + "micrograms-per-cubic-meter": "Microgramos por metro cúbico", + "aqi": "AQI", + "gram-per-cubic-meter": "Gramos por metro cúbico", + "gram-per-kilogram": "Humedad Específica", + "millimeters-per-second": "Milimetros por segundo", + "neper": "Neper", + "bel": "Belio", + "decibel": "Decibelio", + "meters-per-second-squared": "Metros por segundo al cuadrado", + "becquerel": "Becquerel", + "curie": "Curie", + "gray": "Gray", + "sievert": "Sievert", + "roentgen": "Roentgen", + "cps": "Cuentas por segundo", + "rad": "Rad", + "rem": "Rem", + "dps": "Desintegraciones por segundo", + "rutherford": "Rutherford", + "coulombs-per-kilogram": "Culombios por kilogramo", + "becquerels-per-cubic-meter": "Becquerels por metro cúbico", + "curies-per-liter": "Curies por litro", + "becquerels-per-second": "Becquerels por segundo", + "curies-per-second": "Curies por segundo", + "gy-per-second": "Gray por segundo", + "watt-per-steradian": "Watio por estereorradián", + "watt-per-square-metre-steradian": "Watios por metro cuadrado de estereorradián", + "ph-level": "Nivel de pH", + "turbidity": "Turbidez", + "mg-per-liter": "Miligramos por litro", + "microsiemens-per-centimeter": "Microsiemens por centímetro", + "millisiemens-per-meter": "Milisiemens por metro", + "siemens-per-meter": "Siemens por metro", + "kilogram-per-cubic-meter": "Kilogramos por metro cúbico", + "gram-per-cubic-centimeter": "Gramos por centímetro cúbico", + "kilogram-per-square-meter": "Kilogramo por metro cuadrado", + "milligram-per-milliliter": "Miligramo por mililitro", + "pound-per-cubic-foot": "Libra por pie cúbico", + "ounces-per-cubic-inch": "Onzas por pulgada cúbica", + "tons-per-cubic-yard": "Toneladas por yarda cúbica", + "particle-density": "Densidad de partícula", + "kilometers-per-liter": "Kilometros por litro", + "miles-per-gallon": "Millas por galón", + "liters-per-100-km": "Litros por 100 km", + "gallons-per-mile": "Galones por milla", + "liters-per-hour": "Litros por hora", + "gallons-per-hour": "Galones por hora", + "beats-per-minute": "Pulsaciones por minuto", + "millimeters-of-mercury": "Milímetros de mercurio", + "milligrams-per-deciliter": "Miligramos por decilitro", + "g-force": "Fuerza-G", + "kilonewton": "Kilonewton", + "kilogram-force": "Kilogramo-Fuerza", + "pound-force": "Pondio-Fuerza", + "kilopound-force": "Kilopondio-Fuerza", + "dyne": "Dina", + "poundal": "Poundal", + "kip": "Kip", + "gal": "Gal", + "gravity": "Gravedad", + "hectopascal": "Hectopascal", + "atmosphere": "Atmósfera", + "millibars": "Milibares", + "inch-of-mercury": "Pulgada de mercurio", + "richter-scale": "Escala de Richter", + "second": "Segundo", + "minute": "Minuto", + "hour": "Hora", + "day": "Día", + "week": "Semana", + "month": "Mes", + "year": "Año", + "cubic-foot-per-minute": "Pie cúbico por minuto", + "cubic-meters-per-hour": "Metros cúbicos por hora", + "cubic-meters-per-second": "Metros cúbicos por segundo", + "liter-per-second": "Litros por segundo", + "liter-per-minute": "Litros por minuto", + "gallons-per-minute": "Galones por minuto", + "cubic-foot-per-second": "Pie cúbico por segundo", + "milliliters-per-minute": "Mililitros por minuto", + "bit": "Bit", + "byte": "Byte", + "kilobyte": "Kilobyte", + "megabyte": "Megabyte", + "gigabyte": "Gigabyte", + "terabyte": "Terabyte", + "petabyte": "Petabyte", + "exabyte": "Exabyte", + "zettabyte": "Zettabyte", + "yottabyte": "Yottabyte", + "bit-per-second": "Bit por segundo", + "kilobit-per-second": "Kilobit por segundo", + "megabit-per-second": "Megabit por segundo", + "gigabit-per-second": "Gigabit por segundo", + "terabit-per-second": "Terabit por segundo", + "byte-per-second": "Byte por segundo", + "kilobyte-per-second": "Kilobyte por segundo", + "megabyte-per-second": "Megabyte por segundo", + "gigabyte-per-second": "Gigabyte por segundo", + "degree": "Grado", + "radian": "Radian", + "gradian": "Gradian", + "mil": "Mil", + "revolution": "Revolución", + "siemens": "Siemens", + "millisiemens": "Milisiemens", + "microsiemens": "Microsiemens", + "kilosiemens": "Kilosiemens", + "megasiemens": "Megasiemens", + "gigasiemens": "Gigasiemens", + "farad": "Faradio", + "millifarad": "Milifaradio", + "microfarad": "Microfaradio", + "nanofarad": "Nanofaradio", + "picofarad": "Picofaradio", + "kilofarad": "Kilofaradio", + "megafarad": "Megafaradio", + "gigafarad": "Gigafaradio", + "terfarad": "Terfaradio", + "farad-per-meter": "Faradio por metro", + "tesla": "Tesla", + "gauss": "Gauss", + "kilogauss": "Kilogauss", + "millitesla": "Militesla", + "microtesla": "Microtesla", + "nanotesla": "Nanotesla", + "kilotesla": "Kilotesla", + "megatesla": "Megatesla", + "millitesla-square-meters": "militesla por metro cuadrado", + "gamma": "Gamma", + "lambda": "Lambda", + "square-meter-per-second": "Metros cuadrados por segundo", + "square-centimeter-per-second": "Centímetros cuadrados por segundo", + "stoke": "Stoke", + "centistokes": "Centistokes", + "square-foot-per-second": "Pie cuadrado por segundo", + "square-inch-per-second": "Pulgada cuadrada por segundo", + "pascal-second": "Pascal-segundo", + "centipoise": "Centipoise", + "poise": "Poise", + "reynolds": "Reynolds", + "pound-per-foot-hour": "Libra por pie-hora", + "newton-second-per-square-meter": "Newton segundo por metro cuadrado", + "dyne-second-per-square-centimeter": "Dyne segundo por centímetro cuadrado", + "kilogram-per-meter-second": "Kilogramo por metro-segundo", + "tesla-square-meters": "Tesla metros cuadrados", + "maxwell": "Maxwell", + "tesla-per-meter": "Tesla por metro", + "gauss-per-centimeter": "Gauss por centímetro", + "weber": "Weber", + "microweber": "Microweber", + "milliweber": "Miliweber", + "gauss-square-centimeter": "Gauss-centímetro cuadrado", + "kilogauss-square-centimeter": "Kilogauss-centímetro cuadrado", + "henry": "Henrio", + "millihenry": "Milihenrio", + "microhenry": "Microhenrio", + "nanohenry": "Nanohenrio", + "henry-per-meter": "Henrio por metro", + "tesla-meter-per-ampere": "Tesla metro por amperio", + "gauss-per-oersted": "Gauss por Oersted", + "kilogram-per-mole": "Kilogramo por mole", + "gram-per-mole": "Gramo por mole", + "milligram-per-mole": "Miligramo por mole", + "joule-per-mole": "Julios por mole", + "joule-per-mole-kelvin": "Julios por mole-Kelvin", + "millivolts-per-meter": "Milivoltios por metro", + "volts-per-meter": "Voltios por metro", + "kilovolts-per-meter": "Kilovoltios por metro", + "radian-per-second": "Radianes por segundo", + "radian-per-second-squared": "Radianes por segundo al cuadrado", + "revolutions-per-minute-per-second": "Aceleración angular", + "revolutions-per-minute-per-second-squared": "Aceleración angular", + "deg-per-second": "Grados/s", + "degrees-brix": "Grados Brix", + "katal": "Katal", + "katal-per-cubic-metre": "Katal por metro cúbico" }, "user": { "user": "Usuario", @@ -3920,12 +4735,21 @@ "widget-bundle": "Paquetes de Widgets", "all-bundles": "Todos los paquetes", "select-widgets-bundle": "Seleccionar paquete de widgets", + "widgets": "Widgets", + "all-widgets": "Todos los widgets", + "widget": "Widget", + "select-widget": "Seleccionar widget", + "no-widgets-matching": "No se han encontrado widgets que coincidan con '{{entity}}'.", + "no-widgets": "No hay widgets todavía", + "no-widgets-text": "No se han encontrado widgets", "management": "Gestión de Widgets", "editor": "Editor de widgets", "widget-type-not-found": "Problema al cargar la configuración del widget.
Probablemente asociado\n El tipo de widget fue eliminado.", "widget-type-load-error": "El widget no pudo ser cargado debido a estos errores:", "remove": "Eliminar widget", + "delete": "Borrar widget", "edit": "Editar widget", + "edit-widget-type": "Editar tipo de widget", "remove-widget-title": "¿Eliminar el widget '{{widgetTitle}}'?", "remove-widget-text": "Atención, tras la confirmación el widget será eliminado y toda la información relacionada será irrecuperable..", "timeseries": "Series de tiempo", @@ -3941,13 +4765,17 @@ "unable-to-save-widget-error": "Imposible guardar widget! Tiene errores!", "save": "Guardar widget", "saveAs": "Guardar widget como", + "move": "Mover widget", "save-widget-type-as": "Guardar tipo de widget como", "save-widget-type-as-text": "Por favor, ingrese un nuevo titulo y/o seleccione un paquete de destino.", "toggle-fullscreen": "Cambiar a pantalla completa", "run": "Ejecutar widget", + "widget-title": "Título del widget", "title": "Título", "title-required": "Título requerido.", - "type": "Tipo", + "title-max-length": "El título debe ser menor de 256", + "system": "Sistema", + "type": "Tipo de widget", "resources": "Recursos", "resource-url": "URL JavaScript/CSS", "resource-is-module": "Es módulo", @@ -3961,19 +4789,38 @@ "latest-datakey-settings-schema": "Esquema de últimos valores", "widget-settings": "Ajustes de widget", "description": "Descripción", + "tags": "Etiquetas", "image-preview": "Imagen previsualización", "settings-form-selector": "Selector formulario de ajustes", "data-key-settings-form-selector": "Selector formulario de ajustes claves de datos", + "all": "Todos", + "actual": "Actuales", + "deprecated": "Obsoletos", + "has-basic-mode": "Tienen modo básico", + "basic-mode-form-selector": "Selector formulario en modo básico", + "basic-mode": "Básico", + "advanced-mode": "Avanzado", "latest-data-key-settings-form-selector": "Selector formulario de últimos valores", "javascript": "Javascript", "js": "JS", "remove-widget-type-title": "¿Eliminar el tipo del widget '{{widgetName}}'?", "remove-widget-type-text": "Atención, tras la confirmación el tipo será eliminado y la información relacionada será irrecuperable.", "remove-widget-type": "Eliminar tipo de widget.", + "widget-types": "Tipos de Widget", + "delete-widget-type-title": "¿Eliminar el tipo de widget '{{widgetTypeName}}'?", + "delete-widget-type-text": "Atención, tras la confirmación el tipo será eliminado y la información relacionada será irrecuperable.", + "delete-widget-types-title": "¿Eliminar { count, plural, =1 {1 tipo de widget} other {# tipos de widget} }?", + "delete-widget-types-text": "Atención, tras la confirmación los tipos de widget seleccionados serán eliminados y la información relacionada será irrecuperable.", + "delete-widget-type": "Borrar tipo de widget", "add-widget-type": "Agregar nuevo tipo de widget", "widget-type-load-failed-error": "Error al cargar el tipo de widget!", "widget-template-load-failed-error": "Error al cargar la plantilla del widget!", + "details": "Detalles", + "widget-type-details": "Detalles de tipo de widget", "add": "Agregar Widget", + "no-widget-types-text": "No se han encontrado tipos de widget", + "search-widget-types": "Buscar tipos de widget", + "selected-widget-types": "{ count, plural, =1 {1 tipo de widget} other {# tipos de widget} } seleccionados", "undo": "Deshacer cambios", "export": "Exportar widget", "no-data": "No hay datos para mostrar en widget", @@ -3981,7 +4828,8 @@ "alarm-data-overflow": "El widget muestra alarmas para {{allowedEntities}} entidades (máximo permitido) de {{totalEntities}} entidades", "search": "Buscar widget", "filter": "Filtro tipo de widget", - "loading-widgets": "Cargando widgets..." + "loading-widgets": "Cargando widgets...", + "widget-template-error": "Plantilla HTML inválida." }, "widget-action": { "header-button": "Botón de encabezado widget", @@ -3990,6 +4838,9 @@ "open-dashboard": "Navegar hacia otro panel", "custom": "Acción personalizada", "custom-pretty": "Acción personalizada (con plantilla HTML)", + "custom-pretty-error-title": "Diálogo de error personalizado", + "custom-pretty-template-error": "Plantilla de diálogo de error inválida.", + "custom-pretty-controller-error": "Ha ocurrido un error mientras se evaluaba la función.", "mobile-action": "Acción en dispositivo móvil", "target-dashboard-state": "Estado de panel de destino", "target-dashboard-state-required": "Se requiere estado de panel de destino", @@ -4040,6 +4891,7 @@ "widgets-bundle": { "current": "Paquete actual", "widgets-bundles": "Paquete de Widgets", + "widgets-bundle-widgets": "Widgets del paquete de widgets", "add": "Agregar paquete de widgets", "delete": "Eliminar paquete de widgets", "title": "Título", @@ -4062,6 +4914,7 @@ "system": "Widget de Sistema", "import": "Importar paquete de widgets", "export": "Exportar paquete de widgets", + "export-widgets-bundle-widgets-prompt": "Incluir tipos de widget en los datos exportados (de lo contrario, solo se exportarán los FQN de los tipos de widget a los que hace referencia)", "export-failed-error": "Imposible exportar paquete de widgets: {{error}}", "create-new-widgets-bundle": "Crear nuevo paquete de widgets", "widgets-bundle-file": "Archivo de paquete de widgets", @@ -4075,14 +4928,19 @@ "data": "Datos", "settings": "Ajustes", "advanced": "Avanzado", - "title": "Titulo", + "appearance": "Apariencia", + "widget-card": "Tarjeta de widget", + "mobile": "Móvil", + "title": "Título", "title-tooltip": "Tooltip Título", "general-settings": "Ajustes generales", "display-title": "Mostrar titulo", + "card-title": "Título de la tarjeta", "drop-shadow": "Sombra", "enable-fullscreen": "Habilitar pantalla completa", "background-color": "Color de fondo", "text-color": "Color del texto", + "border-radius": "Radio del borde", "padding": "Relleno", "margin": "Margen", "widget-style": "Estilo de widget", @@ -4094,13 +4952,21 @@ "mobile-hide": "Ocultar widget en modo móvil", "desktop-hide": "Ocultar widget en modo escritorio", "units": "Caracter especial a mostrar en el siguiente valor", - "decimals": "Números de dígitos después de la coma", + "units-by-default": "Unidades por defecto", + "decimals": "Decimales", + "decimals-by-default": "Decimales por defecto", + "default-data-key-parameter-hint": "Este parámetro aplica a todos los valores del widget a menos que la configuración de la clave de datos lo anule", + "units-short": "Unidades", + "decimals-short": "Decimales", + "decimals-suffix": "decimales", "timewindow": "Ventana de tiempo", "use-dashboard-timewindow": "Usar ventana de tiempo del Panel", + "use-widget-timewindow": "Usar ventana de tiempo del widget", "display-timewindow": "Mostrar ventana de tiempo", "legend": "Leyenda", "display-legend": "Mostrar leyenda", - "datasources": "Set de datos", + "datasources": "Origen de datos", + "datasource": "Origen de dato", "maximum-datasources": "Un máximo de { count, plural, =1 {1 set de datos es permitido.} other {# set de datos son permitidos} }", "timeseries-key-error": "Se debe especificar al menos un datakey tipo timeseries", "datasource-type": "Tipo", @@ -4129,26 +4995,69 @@ "delete-action-text": "Eliminar la acción de widget con el nombre '{{actionName}}'?", "title-icon": "Título de icono", "display-icon": "Mostrar título de icono", + "card-icon": "Card icon", "icon-color": "Color del icono", "icon-size": "Tamaño del icono", "advanced-settings": "Ajustes avanzados", "data-settings": "Ajustes de datos", + "limits": "Limits", "no-data-display-message": "\"No hay datos que mostrar\" mensaje alternativo", "data-page-size": "Nº Máximo de entidades por origen de datos", - "settings-component-not-found": "Componente de ajustes no encontrado para el selector '{{selector}}'" + "settings-component-not-found": "Componente de ajustes no encontrado para el selector '{{selector}}'", + "preview": "Previsualizar", + "set": "Establecer", + "set-message": "Establecer mensaje", + "advanced-title-style": "Estilo de título avanzado", + "card-style": "Estilo de tarjeta", + "text": "Texto", + "background": "Fondo", + "advanced-widget-style": "Estilo avanzado de widget", + "card-buttons": "Botones de tarjeta", + "show-card-buttons": "Mostrar botones", + "card-border-radius": "Radio del borde", + "card-appearance": "Apariencia", + "color": "Color" }, "widget-type": { "import": "Importar tipo de widget", "export": "Exportar tipo de widget", + "export-widget-types": "Exportar tipos de widget", "export-failed-error": "Imposible exportar tipo de widget: {{error}}", "create-new-widget-type": "Crear nuevo tipo de widget", "widget-type-file": "Archivo de tipo de widget", "invalid-widget-type-file-error": "No se puede importar tipo de widget: Estructura de datos del tipo de widget es inválida." }, "widgets": { + "background": { + "background": "Fondo", + "background-settings": "Ajustes de fondo", + "background-type-image": "Subir imagen", + "background-type-image-url": "URL imagen", + "background-type-color": "Color sólido", + "image-url": "URL imagen", + "overlay": "Capa superpuesta", + "enable-overlay": "Activar capa", + "blur": "Difuminar", + "preview": "Previsualizar" + }, + "battery-level": { + "layout": "Diseño", + "layout-vertical-solid": "Vertical. Sólido", + "layout-horizontal-solid": "Horizontal. Sólido", + "layout-vertical-divided": "Vertical. Dividido", + "layout-horizontal-divided": "Horizontal. Dividido", + "icon": "Icono", + "value": "Valor", + "auto-scale": "Auto escalar", + "battery-level-color": "Color del nivel de batería", + "battery-shape-color": "Color de la forma", + "battery-level-card-style": "Estilo de tarjeta batería" + }, "chart": { "common-settings": "Ajustes comunes", "enable-stacking-mode": "Activar modo de apilamiento (stacking)", + "selection": "Selección de rango de tiempo", + "enable-selection-mode": "Habilitar modo de selección", "line-shadow-size": "Tamaño de sombra (línea)", "display-smooth-lines": "Mostrar líneas suaves (curvas)", "default-bar-width": "Ancho de barra por defecto para datos no agregados (millisegundos)", @@ -4156,10 +5065,12 @@ "bar-alignment-left": "Izquierda", "bar-alignment-right": "Derecha", "bar-alignment-center": "Centro", + "default-font": "Fuente por defecto", "default-font-size": "Tamaño de fuente por defecto", "default-font-color": "Color de fuente por defecto", "thresholds-line-width": "Ancho de línea por defecto para todos los umbrales", "tooltip-settings": "Ajustes de sugerencias (tooltip)", + "tooltip": "Tooltip (sugerencias)", "show-tooltip": "Mostrar sugerencias", "hover-individual-points": "Hover sobre puntos individuales", "show-cumulative-values": "Mostrar valores acumulados en modo apilado", @@ -4237,6 +5148,7 @@ "add-threshold": "Añadir nuevo umbral", "show-values-for-comparison": "Mostrar valores históricos para su comparación", "comparison-values-label": "Etiqueta de valores históricos", + "comparison-line-color": "Color de línea en comparación", "threshold-settings": "Ajustes de umbrales", "use-as-threshold": "Usar valor de clave como umbral", "threshold-line-width": "Ancho de línea (para umbral)", @@ -4245,6 +5157,7 @@ "radius": "Radio", "inner-radius": "Radio interior", "tilt": "Inclinación", + "common-pie-settings-range-error": "El valor debe estar en el rango de 0 a 1", "stroke-settings": "Ajustes de trazo", "width-pixels": "Ancho (pixels)", "show-labels": "Mostrar etiquetas", @@ -4255,7 +5168,34 @@ "border-color": "Color de borde", "legend-settings": "Ajustes de leyenda", "display-legend": "Mostrar leyenda", - "labels-font-color": "Color de texto en leyenda" + "labels-font-color": "Color de texto en leyenda", + "series": "Series", + "add-series": "Añadir series", + "series-settings": "Ajustes de series", + "remove-series": "Eliminar serie", + "no-series": "No hay series configuradas", + "no-series-error": "Al menos se debe especificar una serie", + "chart-appearance": "Apariencia del gráfico", + "vertical-grid-lines": "Líneas de cuadrícula verticales", + "horizontal-grid-lines": "Líneas de cuadrícula horizontales", + "chart-background": "Fondo del gráfico", + "grid-lines-color": "Color de cuadrícula", + "border": "Borde", + "axis": "Eje", + "vertical-axis": "Eje vertical", + "ticks": "Ticks", + "horizontal-axis": "Eje horizontal" + }, + "color": { + "color-settings": "Ajustes de color", + "color-type-constant": "Constante", + "color-type-range": "Rango", + "color-type-function": "Función", + "color": "Color", + "value-range": "Rango de valor", + "from": "Desde", + "to": "A", + "color-function": "Función de color" }, "dashboard-state": { "dashboard-state-settings": "Ajustes estado de panel", @@ -4371,7 +5311,12 @@ "read-only": "Solo lectura", "events-title": "Título del formulario de eventos", "events-filter": "Filtro de eventos", - "event-key-contains": "La clave de evento contiene..." + "event-key-contains": "La clave de evento contiene...", + "show-connector": "Mostrar para el conector", + "connector-state-param-key": "Clave del parámetro de estado del conector", + "status": "Estado", + "message": "Mensaje", + "created-time": "Hora de creación" }, "gauge": { "default-color": "Color por defecto", @@ -4604,6 +5549,9 @@ "input-fields-alignment": "Alineado de campos de entrada", "input-fields-alignment-column": "Columna (por defecto)", "input-fields-alignment-row": "Fila", + "layout": "Diseño", + "row-gap": "Espacio entre filas en píxeles", + "column-gap": "Espacio entre columnas en píxeles", "latitude-field-required": "Campo latitud requerido", "longitude-field-required": "Campo longitud requerido", "attribute-settings": "Ajustes de atributos", @@ -4652,12 +5600,19 @@ "datakey-value-type-date": "Fecha", "datakey-value-type-time": "Hora", "datakey-value-type-select": "Selección", + "datakey-value-type-color": "Color", "value-is-required": "Valor requerido", "ability-to-edit-attribute": "Posibilidad de editar atributo", "ability-to-edit-attribute-editable": "Editable (por defecto)", "ability-to-edit-attribute-disabled": "Desactivado", "ability-to-edit-attribute-readonly": "Sólo lectura", "disable-on-datakey-name": "Desactivar cuando otra clave de datos sea false (especificar nombre de clave de datos)", + "field-appearance": "Apariencia de los campos", + "appearance-fill": "Relleno", + "appearance-outline": "Contorno", + "subscript-sizing": "Tamaño subscript", + "subscript-sizing-fixed": "Fijo", + "subscript-sizing-dynamic": "Dinámico", "slide-toggle-settings": "Ajustes de deslizador", "slide-toggle-label-position": "Posición de etiqueta", "slide-toggle-label-position-after": "Después", @@ -5061,10 +6016,62 @@ "markdown-css": "Markdown/HTML CSS" }, "simple-card": { + "label": "Etiqueta", "label-position": "Posición etiqueta", "label-position-left": "Izquierda", "label-position-top": "Superior" }, + "value-card": { + "layout": "Diseño", + "layout-square": "Cuadrado", + "layout-vertical": "Vertical", + "layout-centered": "Centrado", + "layout-simplified": "Simplificado", + "layout-horizontal": "Horizontal", + "layout-horizontal-reversed": "Horizontal inverso", + "label": "Etiqueta", + "icon": "Icono", + "value": "Valor", + "date": "Fecha", + "value-card-style": "Estilo de tarjeta valores" + }, + "aggregated-value-card": { + "subtitle": "Subtítulo", + "chart": "Gráfico", + "values": "Valores", + "value-appearance": "Apariencia de valores", + "position": "Posición", + "position-center": "Centro", + "position-right-top": "Arriba a la derecha", + "position-right-bottom": "Abajo a la derecha", + "position-left-top": "Arriba a la izquierda", + "position-left-bottom": "Abajo a la izquierda", + "font": "Fuente", + "color": "Color", + "arrow": "Flecha", + "display-up-down-arrow": "Mostrar flecha Arriba/Abajo", + "add-value": "Añadir valor", + "remove-value": "Quitar valor", + "no-values": "No hay valores configurados", + "aggregation": "Agregación", + "aggregated-value-card-style": "Estilo de tarjeta valores agregados" + }, + "alarm-count": { + "alarm-count-card-style": "Estilo de tarjeta contaje de alarmas" + }, + "entity-count": { + "entity-count-card-style": "Estilo de tarjeta contaje de entidades" + }, + "count": { + "layout": "Diseño", + "layout-column": "Columna", + "layout-row": "Fila", + "label": "Etiqueta", + "icon": "Icono", + "icon-background": "Fondo de icono", + "value": "Valor", + "chevron": "Chevron" + }, "table": { "common-table-settings": "Ajustes comunes en tablas", "enable-search": "Activar búsqueda", @@ -5115,7 +6122,21 @@ "allow-alarms-ack": "Permitir reconocimiento de alarmas", "allow-alarms-clear": "Permitir borrado de alarmas", "display-alarm-activity": "Mostrar actividad de alarmas", - "allow-alarms-assign": "Permitir asignar alarmas" + "allow-alarms-assign": "Permitir asignar alarmas", + "columns": "Columnas", + "column-settings": "Ajustes de columnas", + "remove-column": "Quitar columna", + "add-column": "Añadir columna", + "no-columns": "No hay columnas configuradas", + "columns-to-display": "Columnas a Mostrar", + "table-header": "Encabezado de tabla", + "header-buttons": "Botones encabezado", + "table-buttons": "Botones de tabla", + "pagination": "Paginación", + "rows": "Filas", + "timeseries-column-error": "Se debe especificar al menos una columna tipo timeseries", + "table-tabs": "Pestañas de la tabla", + "show-cell-actions-menu-mobile": "Mostrar menú desplegable de acciones de celda en modo móvil" }, "value-source": { "value-source": "Origen valor", @@ -5126,6 +6147,7 @@ "source-entity-attribute": "Atributo entidad de origen" }, "widget-font": { + "font-settings": "Ajustes de fuente", "font-family": "Familia (font family)", "size": "Tamaño", "relative-font-size": "Tamaño fuente relativo (porcentaje)", @@ -5139,7 +6161,10 @@ "font-weight-bolder": "Negrita+", "font-weight-lighter": "Lighter", "color": "Color", - "shadow-color": "Color de sombra" + "shadow-color": "Color de sombra", + "preview": "Previsualizar", + "line-height": "Altura de línea", + "auto": "Auto" }, "home": { "no-data-available": "No hay datos disponibles" @@ -5336,11 +6361,17 @@ } } }, + "color": { + "color": "Color" + }, "icon": { "icon": "Icono", - "select-icon": "Seleccionar iconos", + "icons": "Iconos", + "select-icon": "Seleccionar icono", "material-icons": "Iconos material-design", - "show-all": "Mostrar todos los iconos" + "show-all": "Mostrar todos los iconos", + "search-icon": "Buscar icono", + "no-icons-found": "No se han encontrado iconos que coincidan con '{{iconSearch}}'" }, "phone-input": { "phone-input-label": "Número de teléfono", @@ -5360,7 +6391,8 @@ "node-selected": "Clic en el nodo seleccionado", "element-click": "Clic en el elemento HTML", "pie-slice-click": "Clic en la rebanada", - "row-double-click": "Doble clic en la fila" + "row-double-click": "Doble clic en la fila", + "card-click": "En click de tarjeta" } }, "paginator" : { From 7c174de71da9decd27a38804e7dbafdb358567cc Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 21 Sep 2023 17:48:53 +0200 Subject: [PATCH 114/267] BaseController: log experience improvement. use a child class logger instead of abstract class controller --- .../org/thingsboard/server/controller/BaseController.java | 5 +++-- 1 file changed, 3 insertions(+), 2 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 0af55d7c00..365f1fc379 100644 --- a/application/src/main/java/org/thingsboard/server/controller/BaseController.java +++ b/application/src/main/java/org/thingsboard/server/controller/BaseController.java @@ -21,7 +21,7 @@ import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import lombok.Getter; -import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.MediaType; @@ -174,10 +174,11 @@ import static org.thingsboard.server.common.data.query.EntityKeyType.ENTITY_FIEL import static org.thingsboard.server.controller.UserController.YOU_DON_T_HAVE_PERMISSION_TO_PERFORM_THIS_OPERATION; import static org.thingsboard.server.dao.service.Validator.validateId; -@Slf4j @TbCoreComponent public abstract class BaseController { + private final Logger log = org.slf4j.LoggerFactory.getLogger(getClass()); + /*Swagger UI description*/ @Autowired From 28b23ba9b40e658383b38b0d9a950109b2fd8eaa Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Fri, 29 Sep 2023 11:49:41 +0200 Subject: [PATCH 115/267] fixed AlarmTypes redis cache serialization --- .../server/common/data/EntitySubtype.java | 79 ++----------------- .../server/common/data/page/PageData.java | 2 + .../dao/service/TbCacheSerializationTest.java | 50 ++++++++++++ 3 files changed, 60 insertions(+), 71 deletions(-) create mode 100644 dao/src/test/java/org/thingsboard/server/dao/service/TbCacheSerializationTest.java diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java index a776635c61..b2e78319dd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java @@ -15,80 +15,17 @@ */ package org.thingsboard.server.common.data; +import lombok.Data; import org.thingsboard.server.common.data.id.TenantId; -public class EntitySubtype { +import java.io.Serializable; - private static final long serialVersionUID = 8057240243059922101L; - - private TenantId tenantId; - private EntityType entityType; - private String type; - - public EntitySubtype() { - super(); - } - - public EntitySubtype(TenantId tenantId, EntityType entityType, String type) { - this.tenantId = tenantId; - this.entityType = entityType; - this.type = type; - } - - public TenantId getTenantId() { - return tenantId; - } - - public void setTenantId(TenantId tenantId) { - this.tenantId = tenantId; - } - - public EntityType getEntityType() { - return entityType; - } - - public void setEntityType(EntityType entityType) { - this.entityType = entityType; - } - - public String getType() { - return type; - } +@Data +public class EntitySubtype implements Serializable { - public void setType(String type) { - this.type = type; - } - - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - - EntitySubtype that = (EntitySubtype) o; - - if (tenantId != null ? !tenantId.equals(that.tenantId) : that.tenantId != null) return false; - if (entityType != that.entityType) return false; - return type != null ? type.equals(that.type) : that.type == null; - - } - - @Override - public int hashCode() { - int result = tenantId != null ? tenantId.hashCode() : 0; - result = 31 * result + (entityType != null ? entityType.hashCode() : 0); - result = 31 * result + (type != null ? type.hashCode() : 0); - return result; - } - - @Override - public String toString() { - final StringBuilder sb = new StringBuilder("EntitySubtype{"); - sb.append("tenantId=").append(tenantId); - sb.append(", entityType=").append(entityType); - sb.append(", type='").append(type).append('\''); - sb.append('}'); - return sb.toString(); - } + private static final long serialVersionUID = 8057240243059922101L; + private final TenantId tenantId; + private final EntityType entityType; + private final String type; } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageData.java b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageData.java index 6eb9218956..dd49aa7d97 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/page/PageData.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/page/PageData.java @@ -19,6 +19,7 @@ import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; +import lombok.EqualsAndHashCode; import java.io.Serializable; import java.util.Collections; @@ -27,6 +28,7 @@ import java.util.function.Function; import java.util.stream.Collectors; @ApiModel +@EqualsAndHashCode public class PageData implements Serializable { public static final PageData EMPTY_PAGE_DATA = new PageData<>(); diff --git a/dao/src/test/java/org/thingsboard/server/dao/service/TbCacheSerializationTest.java b/dao/src/test/java/org/thingsboard/server/dao/service/TbCacheSerializationTest.java new file mode 100644 index 0000000000..74306e6234 --- /dev/null +++ b/dao/src/test/java/org/thingsboard/server/dao/service/TbCacheSerializationTest.java @@ -0,0 +1,50 @@ +/** + * Copyright © 2016-2023 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.junit.Assert; +import org.junit.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.thingsboard.server.cache.TbTransactionalCache; +import org.thingsboard.server.common.data.EntitySubtype; +import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.page.PageData; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@DaoSqlTest +public class TbCacheSerializationTest extends AbstractServiceTest { + + @Autowired + TbTransactionalCache> alarmTypesCache; + + @Test + public void AlarmTypesSerializationTest() { + var typesCount = 13; + TenantId tenantId = new TenantId(UUID.randomUUID()); + List types = new ArrayList<>(typesCount); + for (int i = 0; i < typesCount; i++) { + types.add(new EntitySubtype(tenantId, EntityType.ALARM, "alarm_type_" + i)); + } + PageData alarmTypesPage = new PageData<>(types, 1, typesCount, false); + alarmTypesCache.put(tenantId, alarmTypesPage); + PageData foundAlarmTypes = alarmTypesCache.get(tenantId).get(); + Assert.assertEquals(alarmTypesPage, foundAlarmTypes); + } +} From f001b2588d35a62e1a8a195e7f6d37ee74865b5d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 2 Oct 2023 23:03:15 +0200 Subject: [PATCH 116/267] leave toString as-is --- .../thingsboard/server/common/data/EntitySubtype.java | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java index b2e78319dd..93454f6656 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntitySubtype.java @@ -28,4 +28,14 @@ public class EntitySubtype implements Serializable { private final TenantId tenantId; private final EntityType entityType; private final String type; + + @Override + public String toString() { + final StringBuilder sb = new StringBuilder("EntitySubtype{"); + sb.append("tenantId=").append(tenantId); + sb.append(", entityType=").append(entityType); + sb.append(", type='").append(type).append('\''); + sb.append('}'); + return sb.toString(); + } } From 6ec4b8cf7253f85b11c3ec5376285f0281884b53 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 26 Sep 2023 13:17:52 +0300 Subject: [PATCH 117/267] TTL for queue stats and RE exceptions --- .../controller/TenantProfileController.java | 2 + .../DefaultRuleEngineStatisticsService.java | 28 +++--- .../controller/BaseQueueControllerTest.java | 95 +++++++++++++++++++ .../dao/usagerecord/ApiLimitService.java | 5 + .../DefaultTenantProfileConfiguration.java | 2 + .../usagerecord/DefaultApiLimitService.java | 34 +++++-- ...enant-profile-configuration.component.html | 28 ++++++ ...-tenant-profile-configuration.component.ts | 2 + ui-ngx/src/app/shared/models/tenant.model.ts | 4 + .../assets/locale/locale.constant-en_US.json | 6 ++ 10 files changed, 186 insertions(+), 20 deletions(-) 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 a7fe973ec0..6fbee00f7f 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantProfileController.java @@ -151,6 +151,8 @@ public class TenantProfileController extends BaseController { " \"defaultStorageTtlDays\": 0,\n" + " \"alarmsTtlDays\": 0,\n" + " \"rpcTtlDays\": 0,\n" + + " \"queueStatsTtlDays\": 0,\n" + + " \"ruleEngineExceptionsTtlDays\": 0,\n" + " \"warnThreshold\": 0\n" + " }\n" + " },\n" + diff --git a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java index 1b5bfd56d1..30ffb4c8ca 100644 --- a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java +++ b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.stats; import com.google.common.util.concurrent.FutureCallback; import lombok.Data; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.asset.Asset; @@ -26,7 +27,9 @@ 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.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.dao.asset.AssetService; +import org.thingsboard.server.dao.usagerecord.ApiLimitService; import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.util.TbRuleEngineComponent; import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; @@ -37,6 +40,7 @@ import java.util.Collections; import java.util.List; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import java.util.stream.Collectors; @@ -44,9 +48,11 @@ import java.util.stream.Collectors; @TbRuleEngineComponent @Service @Slf4j +@RequiredArgsConstructor public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsService { public static final String TB_SERVICE_QUEUE = "TbServiceQueue"; + public static final String RULE_ENGINE_EXCEPTION = "ruleEngineException"; public static final FutureCallback CALLBACK = new FutureCallback() { @Override public void onSuccess(@Nullable Integer result) { @@ -61,16 +67,10 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS private final TbServiceInfoProvider serviceInfoProvider; private final TelemetrySubscriptionService tsService; - private final Lock lock = new ReentrantLock(); private final AssetService assetService; - private final ConcurrentMap tenantQueueAssets; - - public DefaultRuleEngineStatisticsService(TelemetrySubscriptionService tsService, TbServiceInfoProvider serviceInfoProvider, AssetService assetService) { - this.tsService = tsService; - this.serviceInfoProvider = serviceInfoProvider; - this.assetService = assetService; - this.tenantQueueAssets = new ConcurrentHashMap<>(); - } + private final ApiLimitService apiLimitService; + private final Lock lock = new ReentrantLock(); + private final ConcurrentMap tenantQueueAssets = new ConcurrentHashMap<>(); @Override public void reportQueueStats(long ts, TbRuleEngineConsumerStats ruleEngineStats) { @@ -84,7 +84,9 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS .map(kv -> new BasicTsKvEntry(ts, new LongDataEntry(kv.getKey(), (long) kv.getValue().get()))) .collect(Collectors.toList()); if (!tsList.isEmpty()) { - tsService.saveAndNotifyInternal(tenantId, serviceAssetId, tsList, CALLBACK); + long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getQueueStatsTtlDays); + ttl = TimeUnit.DAYS.toSeconds(ttl); + tsService.saveAndNotifyInternal(tenantId, serviceAssetId, tsList, ttl, CALLBACK); } } } catch (Exception e) { @@ -95,8 +97,10 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS }); ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> { try { - TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry("ruleEngineException", e.toJsonString())); - tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), CALLBACK); + TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString())); + long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getRuleEngineExceptionsTtlDays); + ttl = TimeUnit.DAYS.toSeconds(ttl); + tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), ttl, CALLBACK); } catch (Exception e2) { if (!"Asset is referencing to non-existent tenant!".equalsIgnoreCase(e2.getMessage())) { log.debug("[{}] Failed to store the statistics", tenantId, e2); diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java index 465ec37bb9..9da8c8f496 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java @@ -18,6 +18,12 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; import org.junit.Assert; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.SpyBean; +import org.thingsboard.server.common.data.asset.Asset; +import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -26,13 +32,45 @@ import org.thingsboard.server.common.data.queue.ProcessingStrategyType; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.common.data.queue.SubmitStrategyType; +import org.thingsboard.server.common.msg.queue.RuleEngineException; +import org.thingsboard.server.common.stats.StatsFactory; +import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.service.DaoSqlTest; +import org.thingsboard.server.dao.timeseries.TimeseriesDao; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; +import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService; +import org.thingsboard.server.service.stats.RuleEngineStatisticsService; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; @DaoSqlTest public class BaseQueueControllerTest extends AbstractControllerTest { + @Autowired + private RuleEngineStatisticsService ruleEngineStatisticsService; + @Autowired + private StatsFactory statsFactory; + @SpyBean + private TimeseriesDao timeseriesDao; + @Autowired + private AssetService assetService; + @Test public void testQueueWithServiceTypeRE() throws Exception { loginSysAdmin(); @@ -93,4 +131,61 @@ public class BaseQueueControllerTest extends AbstractControllerTest { .andExpect(status().isOk()); } + @Test + public void testQueueStatsTtl() throws ThingsboardException { + Queue queue = new Queue(); + queue.setName("Test-1"); + queue.setTenantId(TenantId.SYS_TENANT_ID); + + TbRuleEngineProcessingResult testProcessingResult = Mockito.mock(TbRuleEngineProcessingResult.class); + TbProtoQueueMsg msg = new TbProtoQueueMsg<>(UUID.randomUUID(), + TransportProtos.ToRuleEngineMsg.newBuilder() + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .build()); + when(testProcessingResult.getSuccessMap()).thenReturn(Stream.generate(() -> msg) + .limit(5).collect(Collectors.toConcurrentMap(m -> UUID.randomUUID(), m -> m))); + when(testProcessingResult.getFailedMap()).thenReturn(Stream.generate(() -> msg) + .limit(5).collect(Collectors.toConcurrentMap(m -> UUID.randomUUID(), m -> m))); + when(testProcessingResult.getPendingMap()).thenReturn(new ConcurrentHashMap<>()); + RuleEngineException ruleEngineException = new RuleEngineException("Test Exception"); + when(testProcessingResult.getExceptionsMap()).thenReturn(new ConcurrentHashMap<>(Map.of( + tenantId, ruleEngineException + ))); + + TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(queue, statsFactory); + testStats.log(testProcessingResult, true); + + int queueStatsTtlDays = 14; + int ruleEngineExceptionsTtlDays = 7; + updateDefaultTenantProfileConfig(profileConfiguration -> { + profileConfiguration.setQueueStatsTtlDays(queueStatsTtlDays); + profileConfiguration.setRuleEngineExceptionsTtlDays(ruleEngineExceptionsTtlDays); + }); + ruleEngineStatisticsService.reportQueueStats(System.currentTimeMillis(), testStats); + + Asset serviceAsset = assetService.findAssetsByTenantIdAndType(tenantId, TB_SERVICE_QUEUE, new PageLink(100)).getData() + .stream().filter(asset -> asset.getName().startsWith(queue.getName())) + .findFirst().get(); + + ArgumentCaptor ttlCaptor = ArgumentCaptor.forClass(Long.class); + verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { + return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.SUCCESSFUL_MSGS) && + tsKvEntry.getLongValue().get().equals(5L); + }), ttlCaptor.capture()); + verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { + return tsKvEntry.getKey().equals(TbRuleEngineConsumerStats.FAILED_MSGS) && + tsKvEntry.getLongValue().get().equals(5L); + }), ttlCaptor.capture()); + assertThat(ttlCaptor.getAllValues()).allSatisfy(usedTtl -> { + assertThat(usedTtl).isEqualTo(TimeUnit.DAYS.toSeconds(queueStatsTtlDays)); + }); + + verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { + return tsKvEntry.getKey().equals(DefaultRuleEngineStatisticsService.RULE_ENGINE_EXCEPTION) && + tsKvEntry.getJsonValue().get().equals(ruleEngineException.toJsonString()); + }), ttlCaptor.capture()); + assertThat(ttlCaptor.getValue()).isEqualTo(TimeUnit.DAYS.toSeconds(ruleEngineExceptionsTtlDays)); + } + } diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java index cd9524e1b1..69e366327d 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/usagerecord/ApiLimitService.java @@ -17,9 +17,14 @@ package org.thingsboard.server.dao.usagerecord; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; + +import java.util.function.Function; public interface ApiLimitService { boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType); + long getLimit(TenantId tenantId, Function extractor); + } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java index bd2b80f10a..77a7fa8417 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/tenant/profile/DefaultTenantProfileConfiguration.java @@ -82,6 +82,8 @@ public class DefaultTenantProfileConfiguration implements TenantProfileConfigura private int defaultStorageTtlDays; private int alarmsTtlDays; private int rpcTtlDays; + private int queueStatsTtlDays; + private int ruleEngineExceptionsTtlDays; private double warnThreshold; diff --git a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java index d5d19aa453..56bb096b5c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/usagerecord/DefaultApiLimitService.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.usagerecord; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.EntityType; +import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.CustomerId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -27,6 +28,8 @@ import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileCon import org.thingsboard.server.dao.entity.EntityService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; +import java.util.function.Function; + @Service @RequiredArgsConstructor public class DefaultApiLimitService implements ApiLimitService { @@ -36,16 +39,31 @@ public class DefaultApiLimitService implements ApiLimitService { @Override public boolean checkEntitiesLimit(TenantId tenantId, EntityType entityType) { - DefaultTenantProfileConfiguration profileConfiguration = tenantProfileCache.get(tenantId).getDefaultProfileConfiguration(); - long limit = profileConfiguration.getEntitiesLimit(entityType); - if (limit > 0) { - EntityTypeFilter filter = new EntityTypeFilter(); - filter.setEntityType(entityType); - long currentCount = entityService.countEntitiesByQuery(tenantId, new CustomerId(EntityId.NULL_UUID), new EntityCountQuery(filter)); - return currentCount < limit; - } else { + long limit = getLimit(tenantId, profileConfiguration -> profileConfiguration.getEntitiesLimit(entityType)); + if (limit <= 0) { return true; } + + EntityTypeFilter filter = new EntityTypeFilter(); + filter.setEntityType(entityType); + long currentCount = entityService.countEntitiesByQuery(tenantId, new CustomerId(EntityId.NULL_UUID), new EntityCountQuery(filter)); + return currentCount < limit; + } + + @Override + public long getLimit(TenantId tenantId, Function extractor) { + if (tenantId == null || tenantId.isSysTenantId()) { + return 0L; + } + TenantProfile tenantProfile = tenantProfileCache.get(tenantId); + if (tenantProfile == null) { + throw new IllegalArgumentException("Tenant profile not found for tenant " + tenantId); + } + Number value = extractor.apply(tenantProfile.getDefaultProfileConfiguration()); + if (value == null) { + return 0L; + } + return Math.max(0, value.longValue()); } } diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html index c2872d4145..2a4c59a7a2 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.html @@ -262,6 +262,34 @@ +
+ + tenant-profile.queue-stats-ttl-days + + + {{ 'tenant-profile.queue-stats-ttl-days-required' | translate}} + + + {{ 'tenant-profile.queue-stats-ttl-days-range' | translate}} + + + + + tenant-profile.rule-engine-exceptions-ttl-days + + + {{ 'tenant-profile.rule-engine-exceptions-ttl-days-required' | translate}} + + + {{ 'tenant-profile.rule-engine-exceptions-ttl-days-days-range' | translate}} + + + +
diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts index a4915f924b..19eb13540b 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant/default-tenant-profile-configuration.component.ts @@ -90,6 +90,8 @@ export class DefaultTenantProfileConfigurationComponent implements ControlValueA defaultStorageTtlDays: [null, [Validators.required, Validators.min(0)]], alarmsTtlDays: [null, [Validators.required, Validators.min(0)]], rpcTtlDays: [null, [Validators.required, Validators.min(0)]], + queueStatsTtlDays: [null, [Validators.required, Validators.min(0)]], + ruleEngineExceptionsTtlDays: [null, [Validators.required, Validators.min(0)]], tenantServerRestLimitsConfiguration: [null, []], customerServerRestLimitsConfiguration: [null, []], maxWsSessionsPerTenant: [null, [Validators.min(0)]], diff --git a/ui-ngx/src/app/shared/models/tenant.model.ts b/ui-ngx/src/app/shared/models/tenant.model.ts index 9074d599f5..d781dad439 100644 --- a/ui-ngx/src/app/shared/models/tenant.model.ts +++ b/ui-ngx/src/app/shared/models/tenant.model.ts @@ -76,6 +76,8 @@ export interface DefaultTenantProfileConfiguration { defaultStorageTtlDays: number; alarmsTtlDays: number; rpcTtlDays: number; + queueStatsTtlDays: number; + ruleEngineExceptionsTtlDays: number; } export type TenantProfileConfigurations = DefaultTenantProfileConfiguration; @@ -124,6 +126,8 @@ export function createTenantProfileConfiguration(type: TenantProfileType): Tenan defaultStorageTtlDays: 0, alarmsTtlDays: 0, rpcTtlDays: 0, + queueStatsTtlDays: 0, + ruleEngineExceptionsTtlDays: 0 }; configuration = {...defaultConfiguration, type: TenantProfileType.DEFAULT}; break; 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 0867f21114..876fb19afb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4003,6 +4003,12 @@ "rpc-ttl-days": "RPC TTL days", "rpc-ttl-days-required": "RPC TTL days required", "rpc-ttl-days-days-range": "RPC TTL days can't be negative", + "queue-stats-ttl-days": "Queue stats TTL days", + "queue-stats-ttl-days-required": "Queue stats TTL days required", + "queue-stats-ttl-days-range": "Queue stats TTL days can't be negative", + "rule-engine-exceptions-ttl-days": "Rule Engine exceptions TTL days", + "rule-engine-exceptions-ttl-days-required": "Rule Engine exceptions TTL days required", + "rule-engine-exceptions-ttl-days-range": "Rule Engine exceptions TTL days can't be negative", "max-rule-node-executions-per-message": "Rule node per message executions maximum number", "max-rule-node-executions-per-message-required": "MRule node per message executions maximum number is required.", "max-rule-node-executions-per-message-range": "Rule node per message executions maximum number can't be negative", From 69349d5075ea6a8b5603817b441cd45464c47c47 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 3 Oct 2023 12:04:06 +0300 Subject: [PATCH 118/267] TTL for system info --- .../service/system/DefaultSystemInfoService.java | 10 ++++++++-- application/src/main/resources/thingsboard.yml | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java index 80d4cede03..b2412d62d1 100644 --- a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback; import com.google.protobuf.ProtocolStringList; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardThreadFactory; @@ -93,6 +94,11 @@ public class DefaultSystemInfoService extends TbApplicationEventListener telemetry) { ApiUsageState apiUsageState = apiUsageStateClient.getApiUsageState(TenantId.SYS_TENANT_ID); - telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, apiUsageState.getId(), telemetry, CALLBACK); + telemetryService.saveAndNotifyInternal(TenantId.SYS_TENANT_ID, apiUsageState.getId(), telemetry, systemInfoTtlSeconds, CALLBACK); } private List getSystemData(ServiceInfo serviceInfo) { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index d1e5113449..9fda2275f8 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1326,6 +1326,11 @@ metrics: timer: # Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,). percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" + system_info: + # Persist frequency of system info (CPU, memory usage, etc.) in seconds + persist_frequency: "${METRICS_SYSTEM_INFO_PERSIST_FREQUENCY_SECONDS:60}" + # TTL in days for system info timeseries + ttl: "${METRICS_SYSTEM_INFO_TTL_DAYS:7}" vc: # Pool size for handling export tasks From 12d2c26279b1bf687734ba48a29f734e3ecac18b Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 3 Oct 2023 16:12:53 +0300 Subject: [PATCH 119/267] Rule Engine stats: exception message truncation --- .../DefaultRuleEngineStatisticsService.java | 6 ++- .../src/main/resources/thingsboard.yml | 1 + .../controller/BaseQueueControllerTest.java | 47 ++++++++++++++++++- .../server/common/data/StringUtils.java | 13 +++++ .../server/common/data/StringUtilsTest.java | 11 +++++ .../common/msg/queue/RuleEngineException.java | 16 +++++-- .../common/msg/queue/RuleNodeException.java | 4 +- .../thingsboard/common/util/JacksonUtil.java | 27 ++++------- .../server/dao/event/BaseEventService.java | 8 +--- 9 files changed, 100 insertions(+), 33 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java index 30ffb4c8ca..d8d86922cf 100644 --- a/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java +++ b/application/src/main/java/org/thingsboard/server/service/stats/DefaultRuleEngineStatisticsService.java @@ -19,6 +19,7 @@ import com.google.common.util.concurrent.FutureCallback; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.id.AssetId; @@ -72,6 +73,9 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS private final Lock lock = new ReentrantLock(); private final ConcurrentMap tenantQueueAssets = new ConcurrentHashMap<>(); + @Value("${queue.rule-engine.stats.max-error-message-length:4096}") + private int maxErrorMessageLength; + @Override public void reportQueueStats(long ts, TbRuleEngineConsumerStats ruleEngineStats) { String queueName = ruleEngineStats.getQueueName(); @@ -97,7 +101,7 @@ public class DefaultRuleEngineStatisticsService implements RuleEngineStatisticsS }); ruleEngineStats.getTenantExceptions().forEach((tenantId, e) -> { try { - TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString())); + TsKvEntry tsKv = new BasicTsKvEntry(e.getTs(), new JsonDataEntry(RULE_ENGINE_EXCEPTION, e.toJsonString(maxErrorMessageLength))); long ttl = apiLimitService.getLimit(tenantId, DefaultTenantProfileConfiguration::getRuleEngineExceptionsTtlDays); ttl = TimeUnit.DAYS.toSeconds(ttl); tsService.saveAndNotifyInternal(tenantId, getServiceAssetId(tenantId, queueName), Collections.singletonList(tsKv), ttl, CALLBACK); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9fda2275f8..6b11369639 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1248,6 +1248,7 @@ queue: stats: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" + max-error-message-length: "${TB_QUEUE_RULE_ENGINE_MAX_ERROR_MESSAGE_LENGTH:4096}" queues: - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java index 9da8c8f496..845ac49f15 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java @@ -16,15 +16,19 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import org.apache.commons.lang3.RandomStringUtils; import org.junit.Assert; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.test.context.TestPropertySource; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.exception.ThingsboardException; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.queue.ProcessingStrategy; @@ -48,10 +52,13 @@ import java.util.Map; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import java.util.stream.Stream; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; @@ -60,6 +67,9 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import static org.thingsboard.server.dao.asset.BaseAssetService.TB_SERVICE_QUEUE; @DaoSqlTest +@TestPropertySource(properties = { + "queue.rule-engine.stats.max-error-message-length=100" +}) public class BaseQueueControllerTest extends AbstractControllerTest { @Autowired @@ -183,9 +193,44 @@ public class BaseQueueControllerTest extends AbstractControllerTest { verify(timeseriesDao).save(eq(tenantId), eq(serviceAsset.getId()), argThat(tsKvEntry -> { return tsKvEntry.getKey().equals(DefaultRuleEngineStatisticsService.RULE_ENGINE_EXCEPTION) && - tsKvEntry.getJsonValue().get().equals(ruleEngineException.toJsonString()); + tsKvEntry.getJsonValue().get().equals(ruleEngineException.toJsonString(0)); }), ttlCaptor.capture()); assertThat(ttlCaptor.getValue()).isEqualTo(TimeUnit.DAYS.toSeconds(ruleEngineExceptionsTtlDays)); } + @Test + public void testRuleEngineExceptionTruncation() { + Queue queue = new Queue(); + queue.setName("Test-2"); + queue.setTenantId(TenantId.SYS_TENANT_ID); + + TbRuleEngineProcessingResult testProcessingResult = Mockito.mock(TbRuleEngineProcessingResult.class); + when(testProcessingResult.getSuccessMap()).thenReturn(new ConcurrentHashMap<>()); + when(testProcessingResult.getFailedMap()).thenReturn(new ConcurrentHashMap<>()); + when(testProcessingResult.getPendingMap()).thenReturn(new ConcurrentHashMap<>()); + + String largeExceptionMessage = RandomStringUtils.randomAlphabetic(150); + RuleEngineException ruleEngineException = new RuleEngineException(largeExceptionMessage); + when(testProcessingResult.getExceptionsMap()).thenReturn(new ConcurrentHashMap<>(Map.of( + tenantId, ruleEngineException + ))); + + TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(queue, statsFactory); + testStats.log(testProcessingResult, true); + ruleEngineStatisticsService.reportQueueStats(System.currentTimeMillis(), testStats); + + AtomicReference reExceptionTsKvEntryCaptor = new AtomicReference<>(); + verify(timeseriesDao).save(eq(tenantId), any(), argThat(tsKvEntry -> { + if (tsKvEntry.getKey().equals(DefaultRuleEngineStatisticsService.RULE_ENGINE_EXCEPTION)) { + reExceptionTsKvEntryCaptor.set(tsKvEntry); + return true; + } + return false; + }), anyLong()); + TsKvEntry reExceptionTsKvEntry = reExceptionTsKvEntryCaptor.get(); + + String finalErrorMessage = JacksonUtil.toJsonNode(reExceptionTsKvEntry.getJsonValue().get()).get("message").asText(); + assertThat(finalErrorMessage).isEqualTo(largeExceptionMessage.substring(0, 100) + "...[truncated 50 symbols]"); + } + } 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 449f252411..3abbde8401 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 @@ -20,6 +20,7 @@ import org.apache.commons.lang3.RandomStringUtils; import java.security.SecureRandom; import java.util.Base64; +import java.util.function.Function; import static org.apache.commons.lang3.StringUtils.repeat; @@ -228,4 +229,16 @@ public class StringUtils { return generateSafeToken(DEFAULT_TOKEN_LENGTH); } + public static String truncate(String string, int maxLength) { + return truncate(string, maxLength, n -> "...[truncated " + n + " symbols]"); + } + + public static String truncate(String string, int maxLength, Function truncationMarkerFunc) { + if (string == null || maxLength <= 0 || string.length() <= maxLength) { + return string; + } + int truncatedSymbols = string.length() - maxLength; + return string.substring(0, maxLength) + truncationMarkerFunc.apply(truncatedSymbols); + } + } diff --git a/common/data/src/test/java/org/thingsboard/server/common/data/StringUtilsTest.java b/common/data/src/test/java/org/thingsboard/server/common/data/StringUtilsTest.java index 4cf21baa99..b28d64cd2d 100644 --- a/common/data/src/test/java/org/thingsboard/server/common/data/StringUtilsTest.java +++ b/common/data/src/test/java/org/thingsboard/server/common/data/StringUtilsTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.data; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; @@ -37,4 +38,14 @@ class StringUtilsTest { assertThat(StringUtils.contains0x00(sample)).isFalse(); } + @Test + void testTruncate() { + int maxLength = 5; + assertThat(StringUtils.truncate(null, maxLength)).isNull(); + assertThat(StringUtils.truncate("", maxLength)).isEmpty(); + assertThat(StringUtils.truncate("123", maxLength)).isEqualTo("123"); + assertThat(StringUtils.truncate("1234567", maxLength)).isEqualTo("12345...[truncated 2 symbols]"); + assertThat(StringUtils.truncate("1234567", 0)).isEqualTo("1234567"); + } + } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java index b8c713cc6b..9003579c20 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/RuleEngineException.java @@ -19,17 +19,17 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.Getter; import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.StringUtils; @Slf4j public class RuleEngineException extends Exception { protected static final ObjectMapper mapper = new ObjectMapper(); @Getter - private long ts; + private final long ts; public RuleEngineException(String message) { - super(message != null ? message : "Unknown"); - ts = System.currentTimeMillis(); + this(message, null); } public RuleEngineException(String message, Throwable t) { @@ -37,12 +37,18 @@ public class RuleEngineException extends Exception { ts = System.currentTimeMillis(); } - public String toJsonString() { + public String toJsonString(int maxMessageLength) { try { - return mapper.writeValueAsString(mapper.createObjectNode().put("message", getMessage())); + return mapper.writeValueAsString(mapper.createObjectNode() + .put("message", truncateIfNecessary(getMessage(), maxMessageLength))); } catch (JsonProcessingException e) { log.warn("Failed to serialize exception ", e); throw new RuntimeException(e); } } + + protected String truncateIfNecessary(String message, int maxMessageLength) { + return StringUtils.truncate(message, maxMessageLength); + } + } 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 160e2e6f95..4be1875bc1 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 @@ -52,14 +52,14 @@ public class RuleNodeException extends RuleEngineException { } } - public String toJsonString() { + public String toJsonString(int maxMessageLength) { try { return mapper.writeValueAsString(mapper.createObjectNode() .put("ruleNodeId", ruleNodeId.toString()) .put("ruleChainId", ruleChainId.toString()) .put("ruleNodeName", ruleNodeName) .put("ruleChainName", ruleChainName) - .put("message", getMessage())); + .put("message", truncateIfNecessary(getMessage(), maxMessageLength))); } catch (JsonProcessingException e) { log.warn("Failed to serialize exception ", e); throw new RuntimeException(e); 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 7c8d174af2..ee2f91ec4d 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 @@ -70,8 +70,7 @@ public class JacksonUtil { try { return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueType) : null; } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("The given object value: " - + fromValue + " cannot be converted to " + toValueType, e); + throw new IllegalArgumentException("The given object value cannot be converted to " + toValueType + ": " + fromValue, e); } } @@ -79,8 +78,7 @@ public class JacksonUtil { try { return fromValue != null ? OBJECT_MAPPER.convertValue(fromValue, toValueTypeRef) : null; } catch (IllegalArgumentException e) { - throw new IllegalArgumentException("The given object value: " - + fromValue + " cannot be converted to " + toValueTypeRef, e); + throw new IllegalArgumentException("The given object value cannot be converted to " + toValueTypeRef + ": " + fromValue, e); } } @@ -88,8 +86,7 @@ public class JacksonUtil { try { return string != null ? OBJECT_MAPPER.readValue(string, clazz) : null; } catch (IOException e) { - throw new IllegalArgumentException("The given string value: " - + string + " cannot be transformed to Json object", e); + throw new IllegalArgumentException("The given string value cannot be transformed to Json object: " + string, e); } } @@ -97,8 +94,7 @@ public class JacksonUtil { try { return string != null ? OBJECT_MAPPER.readValue(string, valueTypeRef) : null; } catch (IOException e) { - throw new IllegalArgumentException("The given string value: " - + string + " cannot be transformed to Json object", e); + throw new IllegalArgumentException("The given string value cannot be transformed to Json object: " + string, e); } } @@ -106,8 +102,7 @@ public class JacksonUtil { try { return string != null ? OBJECT_MAPPER.readValue(string, javaType) : null; } catch (IOException e) { - throw new IllegalArgumentException("The given String value: " - + string + " cannot be transformed to Json object", e); + throw new IllegalArgumentException("The given String value cannot be transformed to Json object: " + string, e); } } @@ -115,8 +110,7 @@ public class JacksonUtil { try { return bytes != null ? OBJECT_MAPPER.readValue(bytes, clazz) : null; } catch (IOException e) { - throw new IllegalArgumentException("The given string value: " - + Arrays.toString(bytes) + " cannot be transformed to Json object", e); + throw new IllegalArgumentException("The given string value cannot be transformed to Json object: " + Arrays.toString(bytes), e); } } @@ -124,8 +118,7 @@ public class JacksonUtil { try { return OBJECT_MAPPER.readTree(bytes); } catch (IOException e) { - throw new IllegalArgumentException("The given byte[] value: " - + Arrays.toString(bytes) + " cannot be transformed to Json object", e); + throw new IllegalArgumentException("The given byte[] value cannot be transformed to Json object: " + Arrays.toString(bytes), e); } } @@ -133,8 +126,7 @@ public class JacksonUtil { try { return value != null ? OBJECT_MAPPER.writeValueAsString(value) : null; } catch (JsonProcessingException e) { - throw new IllegalArgumentException("The given Json object value: " - + value + " cannot be transformed to a String", e); + throw new IllegalArgumentException("The given Json object value cannot be transformed to a String: " + value, e); } } @@ -208,8 +200,7 @@ public class JacksonUtil { 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); + throw new IllegalArgumentException("The given Json object value cannot be transformed to a String: " + value, e); } } 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 c310141a60..5958a43962 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 @@ -92,12 +92,8 @@ public class BaseEventService implements EventService { private void truncateField(T event, Function getter, BiConsumer setter) { var str = getter.apply(event); - if (StringUtils.isNotEmpty(str)) { - var length = str.length(); - if (length > maxDebugEventSymbols) { - setter.accept(event, str.substring(0, maxDebugEventSymbols) + "...[truncated " + (length - maxDebugEventSymbols) + " symbols]"); - } - } + str = StringUtils.truncate(str, maxDebugEventSymbols); + setter.accept(event, str); } @Override From 1a3d7bfab0a73c67619781dbecf37f6cd1f0b8a2 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 3 Oct 2023 17:18:11 +0300 Subject: [PATCH 120/267] Revert initial delay for saveCurrentSystemInfo --- .../server/service/system/DefaultSystemInfoService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java index b2412d62d1..4b2a3faa2b 100644 --- a/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java +++ b/application/src/main/java/org/thingsboard/server/service/system/DefaultSystemInfoService.java @@ -107,7 +107,7 @@ public class DefaultSystemInfoService extends TbApplicationEventListener Date: Fri, 29 Sep 2023 16:00:39 +0300 Subject: [PATCH 121/267] Remove foreign keys for notification table --- .../main/data/upgrade/3.6.0/schema_update.sql | 26 +++++++++ .../notification/NotificationApiTest.java | 53 +++++++++++++++++++ .../notification/NotificationRuleApiTest.java | 4 +- .../DefaultNotificationRequestService.java | 3 +- .../dao/notification/NotificationDao.java | 4 ++ .../sql/notification/JpaNotificationDao.java | 10 ++++ .../notification/NotificationRepository.java | 6 +++ .../server/dao/user/UserServiceImpl.java | 3 ++ .../resources/sql/schema-entities-idx.sql | 4 ++ .../main/resources/sql/schema-entities.sql | 4 +- 10 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 application/src/main/data/upgrade/3.6.0/schema_update.sql diff --git a/application/src/main/data/upgrade/3.6.0/schema_update.sql b/application/src/main/data/upgrade/3.6.0/schema_update.sql new file mode 100644 index 0000000000..0ad2d97b7a --- /dev/null +++ b/application/src/main/data/upgrade/3.6.0/schema_update.sql @@ -0,0 +1,26 @@ +-- +-- Copyright © 2016-2023 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. +-- + +ALTER TABLE widget_type + ADD COLUMN IF NOT EXISTS tags text[]; + +ALTER TABLE api_usage_state ADD COLUMN IF NOT EXISTS tbel_exec varchar(32); +UPDATE api_usage_state SET tbel_exec = js_exec WHERE tbel_exec IS NULL; + +ALTER TABLE notification DROP CONSTRAINT IF EXISTS fk_notification_request_id; +ALTER TABLE notification DROP CONSTRAINT IF EXISTS fk_notification_recipient_id; +CREATE INDEX IF NOT EXISTS idx_notification_notification_request_id ON notification(request_id); +CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id ON notification_request(tenant_id); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index 1b3fce3c3c..54b3079465 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -25,9 +25,11 @@ import org.mockito.ArgumentCaptor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.client.RestTemplate; import org.thingsboard.rule.engine.api.NotificationCenter; +import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.NotificationRequestId; import org.thingsboard.server.common.data.id.NotificationRuleId; import org.thingsboard.server.common.data.id.NotificationTargetId; import org.thingsboard.server.common.data.id.TenantId; @@ -62,6 +64,7 @@ import org.thingsboard.server.common.data.notification.template.NotificationTemp import org.thingsboard.server.common.data.notification.template.SlackDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.SmsDeliveryMethodNotificationTemplate; import org.thingsboard.server.common.data.notification.template.WebDeliveryMethodNotificationTemplate; +import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.dao.notification.DefaultNotifications; import org.thingsboard.server.dao.notification.NotificationDao; @@ -74,6 +77,7 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.UUID; import java.util.concurrent.TimeUnit; @@ -86,6 +90,7 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest @Slf4j @@ -279,6 +284,49 @@ public class NotificationApiTest extends AbstractNotificationApiTest { assertThat(getMyNotifications(false, 10)).size().isZero(); } + @Test + public void whenTenantIsDeleted_thenDeleteNotifications() throws Exception { + createDifferentTenant(); + NotificationTarget target = createNotificationTarget(savedDifferentTenantUser.getId()); + int notificationsCount = 20; + for (int i = 0; i < notificationsCount; i++) { + NotificationRequest request = submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); + awaitNotificationRequest(request.getId()); + } + List requests = notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(100)).getData(); + assertThat(requests).size().isEqualTo(notificationsCount); + for (NotificationRequest request : requests) { + List notifications = notificationDao.findByRequestId(differentTenantId, request.getId(), new PageLink(100)).getData(); + assertThat(notifications).size().isNotZero(); + } + + deleteDifferentTenant(); + + assertThat(notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(1)).getTotalElements()) + .isZero(); + for (NotificationRequest request : requests) { + assertThat(notificationDao.findByRequestId(differentTenantId, request.getId(), new PageLink(100)).getTotalElements()) + .isZero(); + } + } + + @Test + public void whenUserIsDeleted_thenDeleteNotifications() throws Exception { + NotificationTarget target = createNotificationTarget(customerUserId); + int notificationsCount = 20; + for (int i = 0; i < notificationsCount; i++) { + NotificationRequest request = submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); + awaitNotificationRequest(request.getId()); + } + List notifications = notificationDao.findByRecipientIdAndPageLink(tenantId, customerUserId, new PageLink(100)).getData(); + assertThat(notifications).size().isGreaterThanOrEqualTo(notificationsCount); + + doDelete("/api/user/" + customerUserId).andExpect(status().isOk()); + + notifications = notificationDao.findByRecipientIdAndPageLink(tenantId, customerUserId, new PageLink(100)).getData(); + assertThat(notifications).isEmpty(); + } + @Test public void testNotificationUpdatesForSeveralUsers() throws Exception { int usersCount = 150; @@ -692,6 +740,11 @@ public class NotificationApiTest extends AbstractNotificationApiTest { return future.get(30, TimeUnit.SECONDS); } + private NotificationRequestStats awaitNotificationRequest(NotificationRequestId requestId) { + return await().atMost(30, TimeUnit.SECONDS) + .until(() -> getStats(requestId), Objects::nonNull); + } + private void checkFullNotificationsUpdate(UnreadNotificationsUpdate notificationsUpdate, String... expectedNotifications) { assertThat(notificationsUpdate.getNotifications()).extracting(Notification::getText).containsOnly(expectedNotifications); assertThat(notificationsUpdate.getNotifications()).extracting(Notification::getType).containsOnly(DEFAULT_NOTIFICATION_TYPE); diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 0a2854a28d..d08b1a121b 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -456,7 +456,9 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { loginSysAdmin(); notifications = await().atMost(30, TimeUnit.SECONDS) - .until(() -> getMyNotifications(true, 10), list -> list.size() == 1); + .until(() -> getMyNotifications(true, 10).stream() + .filter(notification -> notification.getType() == NotificationType.RATE_LIMITS) + .collect(Collectors.toList()), list -> list.size() == 1); assertThat(notifications).allSatisfy(notification -> { assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded for tenant " + TEST_TENANT_NAME); }); diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index e951a75c7c..e388c189a0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -42,6 +42,7 @@ import java.util.Optional; public class DefaultNotificationRequestService implements NotificationRequestService, EntityDaoService { private final NotificationRequestDao notificationRequestDao; + private final NotificationDao notificationDao; private final NotificationRequestValidator notificationRequestValidator = new NotificationRequestValidator(); @@ -81,10 +82,10 @@ public class DefaultNotificationRequestService implements NotificationRequestSer return notificationRequestDao.findByRuleIdAndOriginatorEntityId(tenantId, ruleId, originatorEntityId); } - // ON DELETE CASCADE is used: notifications for request are deleted as well @Override public void deleteNotificationRequest(TenantId tenantId, NotificationRequestId requestId) { notificationRequestDao.removeById(tenantId, requestId.getId()); + notificationDao.deleteByRequestId(tenantId, requestId); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java index 1ced714bce..fb3890fcbb 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/NotificationDao.java @@ -41,4 +41,8 @@ public interface NotificationDao extends Dao { int updateStatusByRecipientId(TenantId tenantId, UserId recipientId, NotificationStatus status); + void deleteByRequestId(TenantId tenantId, NotificationRequestId requestId); + + void deleteByRecipientId(TenantId tenantId, UserId recipientId); + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java index 7eeab8c592..21a5ab5c0c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/JpaNotificationDao.java @@ -104,6 +104,16 @@ public class JpaNotificationDao extends JpaAbstractDao getEntityClass() { return NotificationEntity.class; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java index c08a3c290e..586af7d674 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRepository.java @@ -61,6 +61,12 @@ public interface NotificationRepository extends JpaRepository userValidator; private final DataValidator userCredentialsValidator; private final ApplicationEventPublisher eventPublisher; @@ -255,6 +257,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); userCredentialsDao.removeById(tenantId, userCredentials.getUuidId()); userAuthSettingsDao.removeByUserId(userId); + notificationDao.deleteByRecipientId(tenantId, userId); deleteEntityRelations(tenantId, userId); userDao.removeById(tenantId, userId.getId()); eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId)); diff --git a/dao/src/main/resources/sql/schema-entities-idx.sql b/dao/src/main/resources/sql/schema-entities-idx.sql index 675fcd3ec0..68eede5ce4 100644 --- a/dao/src/main/resources/sql/schema-entities-idx.sql +++ b/dao/src/main/resources/sql/schema-entities-idx.sql @@ -104,6 +104,8 @@ CREATE INDEX IF NOT EXISTS idx_notification_rule_tenant_id_trigger_type_created_ CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id_user_created_time ON notification_request(tenant_id, created_time DESC) WHERE originator_entity_type = 'USER'; +CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id ON notification_request(tenant_id); + CREATE INDEX IF NOT EXISTS idx_notification_request_rule_id_originator_entity_id ON notification_request(rule_id, originator_entity_id) WHERE originator_entity_type = 'ALARM'; @@ -112,6 +114,8 @@ CREATE INDEX IF NOT EXISTS idx_notification_request_status ON notification_reque CREATE INDEX IF NOT EXISTS idx_notification_id ON notification(id); +CREATE INDEX IF NOT EXISTS idx_notification_notification_request_id ON notification(request_id); + CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_created_time ON notification(recipient_id, created_time DESC); CREATE INDEX IF NOT EXISTS idx_notification_recipient_id_unread ON notification(recipient_id) WHERE status <> 'READ'; diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 4df73de9d6..bc49142e44 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -851,8 +851,8 @@ CREATE TABLE IF NOT EXISTS notification_request ( CREATE TABLE IF NOT EXISTS notification ( id UUID NOT NULL, created_time BIGINT NOT NULL, - request_id UUID NULL CONSTRAINT fk_notification_request_id REFERENCES notification_request(id) ON DELETE CASCADE, - recipient_id UUID NOT NULL CONSTRAINT fk_notification_recipient_id REFERENCES tb_user(id) ON DELETE CASCADE, + request_id UUID, + recipient_id UUID NOT NULL, type VARCHAR(50) NOT NULL, subject VARCHAR(255), body VARCHAR(1000) NOT NULL, From c0294e387854de892920ad4540f637912371e01f Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 3 Oct 2023 17:29:28 +0300 Subject: [PATCH 122/267] Don't delete notifications when recipient is deleted --- .../service/ttl/AlarmsCleanUpService.java | 1 - .../ttl/NotificationsCleanUpService.java | 4 +-- .../notification/NotificationApiTest.java | 28 +------------------ .../DefaultNotificationRequestService.java | 1 + .../insert/sql/SqlPartitioningRepository.java | 2 +- .../server/dao/user/UserServiceImpl.java | 3 -- 6 files changed, 5 insertions(+), 34 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java index 2f84767eff..416f95cf96 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/AlarmsCleanUpService.java @@ -92,7 +92,6 @@ public class AlarmsCleanUpService { while (true) { PageData toRemove = alarmDao.findAlarmsIdsByEndTsBeforeAndTenantId(expirationTime, tenantId, removalBatchRequest); for (AlarmId alarmId : toRemove.getData()) { - relationService.deleteEntityRelations(tenantId, alarmId); Alarm alarm = alarmService.delAlarm(tenantId, alarmId, false).getAlarm(); if (alarm != null) { entityActionService.pushEntityActionToRuleEngine(alarm.getOriginator(), alarm, tenantId, null, ActionType.ALARM_DELETE, null); diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/NotificationsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/NotificationsCleanUpService.java index 65b04ef0ab..b7e6e57e04 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/NotificationsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/NotificationsCleanUpService.java @@ -63,8 +63,8 @@ public class NotificationsCleanUpService extends AbstractCleanUpService { if (lastRemovedNotificationTs > 0) { long gap = TimeUnit.MINUTES.toMillis(10); long requestExpTime = lastRemovedNotificationTs - TimeUnit.SECONDS.toMillis(NotificationRequestConfig.MAX_SENDING_DELAY) - gap; - // TODO: double-check this - notificationRequestDao.removeAllByCreatedTimeBefore(requestExpTime); + int removed = notificationRequestDao.removeAllByCreatedTimeBefore(requestExpTime); + log.info("Removed {} outdated notification requests older than {}", removed, requestExpTime); } } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index 54b3079465..21d29833b9 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -90,7 +90,6 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.verify; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @DaoSqlTest @Slf4j @@ -285,7 +284,7 @@ public class NotificationApiTest extends AbstractNotificationApiTest { } @Test - public void whenTenantIsDeleted_thenDeleteNotifications() throws Exception { + public void whenTenantIsDeleted_thenDeleteNotificationRequests() throws Exception { createDifferentTenant(); NotificationTarget target = createNotificationTarget(savedDifferentTenantUser.getId()); int notificationsCount = 20; @@ -295,36 +294,11 @@ public class NotificationApiTest extends AbstractNotificationApiTest { } List requests = notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(100)).getData(); assertThat(requests).size().isEqualTo(notificationsCount); - for (NotificationRequest request : requests) { - List notifications = notificationDao.findByRequestId(differentTenantId, request.getId(), new PageLink(100)).getData(); - assertThat(notifications).size().isNotZero(); - } deleteDifferentTenant(); assertThat(notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(1)).getTotalElements()) .isZero(); - for (NotificationRequest request : requests) { - assertThat(notificationDao.findByRequestId(differentTenantId, request.getId(), new PageLink(100)).getTotalElements()) - .isZero(); - } - } - - @Test - public void whenUserIsDeleted_thenDeleteNotifications() throws Exception { - NotificationTarget target = createNotificationTarget(customerUserId); - int notificationsCount = 20; - for (int i = 0; i < notificationsCount; i++) { - NotificationRequest request = submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); - awaitNotificationRequest(request.getId()); - } - List notifications = notificationDao.findByRecipientIdAndPageLink(tenantId, customerUserId, new PageLink(100)).getData(); - assertThat(notifications).size().isGreaterThanOrEqualTo(notificationsCount); - - doDelete("/api/user/" + customerUserId).andExpect(status().isOk()); - - notifications = notificationDao.findByRecipientIdAndPageLink(tenantId, customerUserId, new PageLink(100)).getData(); - assertThat(notifications).isEmpty(); } @Test diff --git a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java index e388c189a0..0a11c058e8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/notification/DefaultNotificationRequestService.java @@ -98,6 +98,7 @@ public class DefaultNotificationRequestService implements NotificationRequestSer notificationRequestDao.updateById(tenantId, requestId, requestStatus, stats); } + // notifications themselves are left in the database until removed by ttl @Override public void deleteNotificationRequestsByTenantId(TenantId tenantId) { notificationRequestDao.removeByTenantId(tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java index 60614e8c90..e317e6d7c0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java @@ -140,7 +140,7 @@ public class SqlPartitioningRepository { try { partitions.add(Long.parseLong(partitionTsStr)); } catch (NumberFormatException nfe) { - log.warn("Failed to parse table name: {}", partitionTableName); + log.debug("Failed to parse table name: {}", partitionTableName); } } return partitions; 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 521b1dbd4d..9776e5fe51 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 @@ -49,7 +49,6 @@ import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; import org.thingsboard.server.dao.exception.IncorrectParameterException; -import org.thingsboard.server.dao.notification.NotificationDao; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; @@ -86,7 +85,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic private final UserDao userDao; private final UserCredentialsDao userCredentialsDao; private final UserAuthSettingsDao userAuthSettingsDao; - private final NotificationDao notificationDao; private final DataValidator userValidator; private final DataValidator userCredentialsValidator; private final ApplicationEventPublisher eventPublisher; @@ -257,7 +255,6 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic UserCredentials userCredentials = userCredentialsDao.findByUserId(tenantId, userId.getId()); userCredentialsDao.removeById(tenantId, userCredentials.getUuidId()); userAuthSettingsDao.removeByUserId(userId); - notificationDao.deleteByRecipientId(tenantId, userId); deleteEntityRelations(tenantId, userId); userDao.removeById(tenantId, userId.getId()); eventPublisher.publishEvent(new UserCredentialsInvalidationEvent(userId)); From d33d847c0c24de4b2944b577a27d9719fb71b664 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 5 Oct 2023 09:56:23 +0200 Subject: [PATCH 123/267] ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE increased from 4 to 8 --- .../thingsboard/server/actors/service/DefaultActorService.java | 2 +- application/src/main/resources/thingsboard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java index 380da71443..87831cb8f6 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java @@ -74,7 +74,7 @@ public class DefaultActorService extends TbApplicationEventListener Date: Thu, 5 Oct 2023 10:41:29 +0200 Subject: [PATCH 124/267] SQL_ATTRIBUTES_BATCH_SIZE decreased from 10k down to 1k to improve concurrent updates on maximum load --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 0b012ba96c..9827a58a53 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -268,8 +268,8 @@ cassandra: sql: # Specify batch size for persisting attribute updates attributes: - batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}" - batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}" + batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:1000}" + batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:50}" stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" 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 value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" From b6b4124625e2203731953245761f4ade819acb93 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 5 Oct 2023 10:41:43 +0200 Subject: [PATCH 125/267] SQL_TS_LATEST_BATCH_SIZE decreased from 10k down to 1k to improve concurrent updates on maximum load --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9827a58a53..4a3023d48f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -280,8 +280,8 @@ sql: 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 value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" ts_latest: - batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}" - batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}" + batch_size: "${SQL_TS_LATEST_BATCH_SIZE:1000}" + batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:50}" stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}" 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}" From 6809d374a6e61be66af2356c33722233a9aab403 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 5 Oct 2023 09:56:23 +0200 Subject: [PATCH 126/267] ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE increased from 4 to 8 --- .../thingsboard/server/actors/service/DefaultActorService.java | 2 +- application/src/main/resources/thingsboard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java index 380da71443..87831cb8f6 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/DefaultActorService.java @@ -74,7 +74,7 @@ public class DefaultActorService extends TbApplicationEventListener Date: Thu, 5 Oct 2023 10:41:29 +0200 Subject: [PATCH 127/267] SQL_ATTRIBUTES_BATCH_SIZE decreased from 10k down to 1k to improve concurrent updates on maximum load --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 0b012ba96c..9827a58a53 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -268,8 +268,8 @@ cassandra: sql: # Specify batch size for persisting attribute updates attributes: - batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}" - batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}" + batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:1000}" + batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:50}" stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" 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 value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" From c57f0bb8aa629cfcd260f1070db41d66c56bea12 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 5 Oct 2023 10:41:43 +0200 Subject: [PATCH 128/267] SQL_TS_LATEST_BATCH_SIZE decreased from 10k down to 1k to improve concurrent updates on maximum load --- application/src/main/resources/thingsboard.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9827a58a53..4a3023d48f 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -280,8 +280,8 @@ sql: 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 value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" ts_latest: - batch_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}" - batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}" + batch_size: "${SQL_TS_LATEST_BATCH_SIZE:1000}" + batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:50}" stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}" 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}" From 31f3c2a824a534c830aefc6d8122884859f5a2b6 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Thu, 5 Oct 2023 11:39:11 +0200 Subject: [PATCH 129/267] CachedAttributesService find() many refactored in non-blocking manner --- .../dao/attributes/CachedAttributesService.java | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java index faff81670b..9a1a1b7ee3 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/attributes/CachedAttributesService.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.stats.DefaultCounter; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.dao.cache.CacheExecutorService; import org.thingsboard.server.dao.service.Validator; +import org.thingsboard.server.dao.sql.JpaExecutorService; import javax.annotation.PostConstruct; import java.util.ArrayList; @@ -61,6 +62,7 @@ public class CachedAttributesService implements AttributesService { public static final String LOCAL_CACHE_TYPE = "caffeine"; private final AttributesDao attributesDao; + private final JpaExecutorService jpaExecutorService; private final CacheExecutorService cacheExecutorService; private final DefaultCounter hitCounter; private final DefaultCounter missCounter; @@ -73,10 +75,12 @@ public class CachedAttributesService implements AttributesService { private boolean valueNoXssValidation; public CachedAttributesService(AttributesDao attributesDao, + JpaExecutorService jpaExecutorService, StatsFactory statsFactory, CacheExecutorService cacheExecutorService, TbTransactionalCache cache) { this.attributesDao = attributesDao; + this.jpaExecutorService = jpaExecutorService; this.cacheExecutorService = cacheExecutorService; this.cache = cache; @@ -134,12 +138,14 @@ public class CachedAttributesService implements AttributesService { } @Override - public ListenableFuture> find(TenantId tenantId, EntityId entityId, String scope, Collection attributeKeys) { + public ListenableFuture> find(TenantId tenantId, EntityId entityId, String scope, final Collection attributeKeysNonUnique) { validate(entityId, scope); - attributeKeys = new LinkedHashSet<>(attributeKeys); // deduplicate the attributes + final var attributeKeys = new LinkedHashSet<>(attributeKeysNonUnique); // deduplicate the attributes attributeKeys.forEach(attributeKey -> Validator.validateString(attributeKey, "Incorrect attribute key " + attributeKey)); - Map> wrappedCachedAttributes = findCachedAttributes(entityId, scope, attributeKeys); + //CacheExecutor for Redis or DirectExecutor for local Caffeine + return Futures.transformAsync(cacheExecutor.submit(() -> findCachedAttributes(entityId, scope, attributeKeys)), + wrappedCachedAttributes -> { List cachedAttributes = wrappedCachedAttributes.values().stream() .map(TbCacheValueWrapper::get) @@ -155,7 +161,8 @@ public class CachedAttributesService implements AttributesService { List notFoundKeys = notFoundAttributeKeys.stream().map(k -> new AttributeCacheKey(scope, entityId, k)).collect(Collectors.toList()); - return cacheExecutor.submit(() -> { + // DB call should run in DB executor, not in cache-related executor + return jpaExecutorService.submit(() -> { var cacheTransaction = cache.newTransactionForKeys(notFoundKeys); try { log.trace("[{}][{}] Lookup attributes from db: {}", entityId, scope, notFoundAttributeKeys); @@ -179,6 +186,8 @@ public class CachedAttributesService implements AttributesService { throw e; } }); + + }, MoreExecutors.directExecutor()); // cacheExecutor analyse and returns results or submit to DB executor } private Map> findCachedAttributes(EntityId entityId, String scope, Collection attributeKeys) { From 9788a87ca38db8d7233520dcdb87bfa5e1158936 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 4 Oct 2023 16:54:19 +0300 Subject: [PATCH 130/267] Fix notification requests deletion test; drop all notifications after test --- .../service/notification/AbstractNotificationApiTest.java | 4 ++++ .../server/service/notification/NotificationApiTest.java | 5 +++-- .../server/service/notification/NotificationRuleApiTest.java | 4 +--- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java index 104b5afef4..27a0eed1a4 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/AbstractNotificationApiTest.java @@ -61,6 +61,7 @@ import org.thingsboard.server.dao.notification.NotificationRequestService; import org.thingsboard.server.dao.notification.NotificationRuleService; import org.thingsboard.server.dao.notification.NotificationTargetService; import org.thingsboard.server.dao.notification.NotificationTemplateService; +import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; import java.net.URISyntaxException; import java.util.Arrays; @@ -90,6 +91,8 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest protected NotificationTargetService notificationTargetService; @Autowired protected NotificationRequestService notificationRequestService; + @Autowired + protected SqlPartitioningRepository partitioningRepository; public static final String DEFAULT_NOTIFICATION_SUBJECT = "Just a test"; public static final NotificationType DEFAULT_NOTIFICATION_TYPE = NotificationType.GENERAL; @@ -100,6 +103,7 @@ public abstract class AbstractNotificationApiTest extends AbstractControllerTest notificationRuleService.deleteNotificationRulesByTenantId(TenantId.SYS_TENANT_ID); notificationTemplateService.deleteNotificationTemplatesByTenantId(TenantId.SYS_TENANT_ID); notificationTargetService.deleteNotificationTargetsByTenantId(TenantId.SYS_TENANT_ID); + partitioningRepository.dropPartitionsBefore("notification", Long.MAX_VALUE, 1); } protected NotificationTarget createNotificationTarget(UserId... usersIds) { diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java index 21d29833b9..26be4e9bd3 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationApiTest.java @@ -286,18 +286,19 @@ public class NotificationApiTest extends AbstractNotificationApiTest { @Test public void whenTenantIsDeleted_thenDeleteNotificationRequests() throws Exception { createDifferentTenant(); + TenantId tenantId = differentTenantId; NotificationTarget target = createNotificationTarget(savedDifferentTenantUser.getId()); int notificationsCount = 20; for (int i = 0; i < notificationsCount; i++) { NotificationRequest request = submitNotificationRequest(target.getId(), "Test " + i, NotificationDeliveryMethod.WEB); awaitNotificationRequest(request.getId()); } - List requests = notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(100)).getData(); + List requests = notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(tenantId, EntityType.USER, new PageLink(100)).getData(); assertThat(requests).size().isEqualTo(notificationsCount); deleteDifferentTenant(); - assertThat(notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(differentTenantId, EntityType.USER, new PageLink(1)).getTotalElements()) + assertThat(notificationRequestService.findNotificationRequestsByTenantIdAndOriginatorType(tenantId, EntityType.USER, new PageLink(1)).getTotalElements()) .isZero(); } diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index d08b1a121b..0a2854a28d 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -456,9 +456,7 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { loginSysAdmin(); notifications = await().atMost(30, TimeUnit.SECONDS) - .until(() -> getMyNotifications(true, 10).stream() - .filter(notification -> notification.getType() == NotificationType.RATE_LIMITS) - .collect(Collectors.toList()), list -> list.size() == 1); + .until(() -> getMyNotifications(true, 10), list -> list.size() == 1); assertThat(notifications).allSatisfy(notification -> { assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded for tenant " + TEST_TENANT_NAME); }); From 261bec2b39b5dfbaac1fdf7809f5a8cd0ad6aed2 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 5 Oct 2023 14:24:33 +0300 Subject: [PATCH 131/267] added missed yml parameter descriptions, script that check description exists for all parameters, added github action that run script --- .../check_yml_parameter_descriptions.yml | 24 + .../src/main/resources/thingsboard.yml | 641 +++++++++++++----- pull_request_template.md | 1 + tools/src/main/python/check_yml_file.py | 105 +++ 4 files changed, 608 insertions(+), 163 deletions(-) create mode 100644 .github/workflows/check_yml_parameter_descriptions.yml create mode 100644 tools/src/main/python/check_yml_file.py diff --git a/.github/workflows/check_yml_parameter_descriptions.yml b/.github/workflows/check_yml_parameter_descriptions.yml new file mode 100644 index 0000000000..240222d1b1 --- /dev/null +++ b/.github/workflows/check_yml_parameter_descriptions.yml @@ -0,0 +1,24 @@ +name: Check yml parameters have description +on: + pull_request: + paths: + - 'application/src/main/resources/thingsboard.yml' +jobs: + build: + name: check + runs-on: ubuntu-20.04 + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10.2" + architecture: "x64" + env: + AGENT_TOOLSDIRECTORY: /opt/hostedtoolcache + + - name: Run Verification Script + run: python3 tools/src/main/python/check_env_variables.py diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index d1e5113449..f04d2b8767 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -14,6 +14,7 @@ # limitations under the License. # +# Server common properties server: # Server bind address address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -53,18 +54,27 @@ server: http2: # Enable/disable HTTP/2 support enabled: "${HTTP2_ENABLED:true}" + # Log errors with stacktrace when REST API throws exception with message "Please contact sysadmin" log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: + # Timeout for sending data to client WebSocket session in milliseconds send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" # recommended timeout >= 30 seconds. Platform will attempt to send 'ping' request 3 times within the timeout ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:30000}" dynamic_page_link: + # Refresh rate of the dynamic alarm end entity data queries refresh_interval: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_INTERVAL_SEC:60}" + # Thread pool size to execute dynamic queries refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" + # Maximum number of dynamic queries per refresh interval. For example, no more than 10 alarm queries executed by user simultaneously in all browsers. max_alarm_queries_per_refresh_interval: "${TB_SERVER_WS_MAX_ALARM_QUERIES_PER_REFRESH_INTERVAL:10}" + # Maximum number of dynamic queries per user. For example, no more than 10 alarm widgets opened by user simultaneously in all browsers< max_per_user: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_MAX_PER_USER:10}" + # Maximum number of entities returned for single entity subscription. For example, no more than 10 000 entities on the map widget max_entities_per_data_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_DATA_SUBSCRIPTION:10000}" + # Maximum number of alarms returned for single alarm subscription. For example, no more than 10 000 alarms on the alarm widget max_entities_per_alarm_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_ALARM_SUBSCRIPTION:10000}" + # Maximum queue size of the websocket updates per session. This restriction prevents infinite updates of WS max_queue_messages_per_session: "${TB_SERVER_WS_DEFAULT_QUEUE_MESSAGES_PER_SESSION:1000}" rest: server_side_rpc: @@ -75,6 +85,7 @@ server: # Default value of the server side RPC timeout. default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" rate_limits: + # Limit that prohibits resetting the password for the user too often. The value of rate limit. By default, no more than 5 requests per hour reset_password_per_user: "${RESET_PASSWORD_PER_USER_RATE_LIMIT_CONFIGURATION:5:3600}" # Application info @@ -101,9 +112,12 @@ zk: # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cluster properties cluster: stats: + # Enable/Disable the cluster statistics. Calculates number of messages sent between cluster nodes based on each type enabled: "${TB_CLUSTER_STATS_ENABLED:false}" + # Interval of printing the cluster stats to the log file print_interval_ms: "${TB_CLUSTER_STATS_PRINT_INTERVAL_MS:10000}" # Plugins configuration parameters @@ -117,7 +131,7 @@ security: jwt: # Since 3.4.2 values are persisted to the database during install or upgrade. On Install, the key will be generated randomly if no custom value set. You can change it later from Web UI under SYS_ADMIN tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:9000}" # Number of seconds (2.5 hours) refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:604800}" # Number of seconds (1 week). - tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" + tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" # User JWT Token issuer tokenSigningKey: "${JWT_TOKEN_SIGNING_KEY:thingsboardDefaultSigningKey}" # Base64 encoded # Enable/disable access to Tenant Administrators JWT token by System Administrator or Customer Users JWT token by Tenant Administrator user_token_access_enabled: "${SECURITY_USER_TOKEN_ACCESS_ENABLED:true}" @@ -129,28 +143,37 @@ security: # Time allowed to claim the device in milliseconds duration: "${SECURITY_CLAIM_DURATION:86400000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value basic: + # Enable/Disable basic security options enabled: "${SECURITY_BASIC_ENABLED:false}" oauth2: # Redirect URL where access code from external user management system will be processed loginProcessingUrl: "${SECURITY_OAUTH2_LOGIN_PROCESSING_URL:/login/oauth2/code/}" githubMapper: + # The email addresses that will be mapped from the URL emailUrl: "${SECURITY_OAUTH2_GITHUB_MAPPER_EMAIL_URL_KEY:https://api.github.com/user/emails}" java_cacerts: + # CA certificates keystore default path. Typically this keystore is at JAVA_HOME/lib/security/cacerts path: "${SECURITY_JAVA_CACERTS_PATH:${java.home}/lib/security/cacerts}" + # The password of the cacerts keystore file password: "${SECURITY_JAVA_CACERTS_PASSWORD:changeit}" mail: oauth2: - refreshTokenCheckingInterval: "${REFRESH_TOKEN_EXPIRATION_CHECKING_INTERVAL:86400}" # Number of seconds (1 day). + # Interval to check refresh token is going to expire in seconds(by default 1 day). + refreshTokenCheckingInterval: "${REFRESH_TOKEN_EXPIRATION_CHECKING_INTERVAL:86400}" # Usage statistics parameters usage: stats: report: + # Enable/Disable collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics is sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" check: + # Interval of checking the start of next cycle and re-enabling the blocked tenants/customers cycle: "${USAGE_STATS_CHECK_CYCLE:60000}" # In milliseconds. Default value is 3 minutes gauge_report_interval: "${USAGE_STATS_GAUGE_REPORT_INTERVAL:180000}" @@ -169,6 +192,7 @@ ui: # Base url for UI help assets base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.6}" +# Database telemetry parameters database: ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records ts: @@ -194,10 +218,12 @@ cassandra: hostname_validation: "${CASSANDRA_SSL_HOSTNAME_VALIDATION:true}" # Set trust store for client authentication of server (optional, uses trust store from default SSLContext if not set) trust_store: "${CASSANDRA_SSL_TRUST_STORE:}" + # The password for Cassandra trust store key trust_store_password: "${CASSANDRA_SSL_TRUST_STORE_PASSWORD:}" # Set key store for server authentication of client (optional, uses key store from default SSLContext if not set) # A key store is only needed if the Cassandra server requires client authentication key_store: "${CASSANDRA_SSL_KEY_STORE:}" + # The password for Cassandra key store key_store_password: "${CASSANDRA_SSL_KEY_STORE_PASSWORD:}" # Comma separated list of cipher suites (optional, uses Java default cipher suites if not set) cipher_suites: "${CASSANDRA_SSL_CIPHER_SUITES:}" @@ -211,7 +237,9 @@ cassandra: init_timeout_ms: "${CASSANDRA_CLUSTER_INIT_TIMEOUT_MS:300000}" # Specify cassandra claster initialization retry interval (if no hosts available during startup) init_retry_interval_ms: "${CASSANDRA_CLUSTER_INIT_RETRY_INTERVAL_MS:3000}" + # Cassandra max local requests per connection max_requests_per_connection_local: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_LOCAL:32768}" + # Cassandra max remote requests per connection max_requests_per_connection_remote: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_REMOTE:32768}" # Credential parameters credentials: "${CASSANDRA_USE_CREDENTIALS:false}" @@ -230,72 +258,93 @@ cassandra: # Cassandra cluster connection socket parameters # socket: + # Sets the timeout, in millisecond, of a native connection from ThingsBoard to Cassandra. The default value is 5000 connect_timeout: "${CASSANDRA_SOCKET_TIMEOUT:5000}" + # Timeout before closing the connection. Value set in milliseconds read_timeout: "${CASSANDRA_SOCKET_READ_TIMEOUT:20000}" + # Gets if TCP keep-alive must be used keep_alive: "${CASSANDRA_SOCKET_KEEP_ALIVE:true}" + # Enable/Disable reuse-address.The socket option allows for the reuse of local addresses and ports reuse_address: "${CASSANDRA_SOCKET_REUSE_ADDRESS:true}" + # Sets the linger-on-close timeout. By default, this option is not set by the driver. The actual value will be the default from the underlying Netty transport so_linger: "${CASSANDRA_SOCKET_SO_LINGER:}" + # Enable/Disable Nagle's algorithm tcp_no_delay: "${CASSANDRA_SOCKET_TCP_NO_DELAY:false}" + # Sets a hint to the size of the underlying buffers for incoming network I/O. By default, this option is not set by the driver. The actual value will be the default from the underlying Netty transport receive_buffer_size: "${CASSANDRA_SOCKET_RECEIVE_BUFFER_SIZE:}" + # Returns the hint to the size of the underlying buffers for outgoing network I/O. By default, this option is not set by the driver. The actual value will be the default from the underlying Netty transport send_buffer_size: "${CASSANDRA_SOCKET_SEND_BUFFER_SIZE:}" # Cassandra cluster connection query parameters # query: + # Consistency levels in Cassandra can be configured to manage availability versus data accuracy. The consistency level defaults to ONE for all write and read operations read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}" + # Consistency levels in Cassandra can be configured to manage availability versus data accuracy. The consistency level defaults to ONE for all write and read operations write_consistency_level: "${CASSANDRA_WRITE_CONSISTENCY_LEVEL:ONE}" + # The fetch size specifies how many rows will be returned at once by Cassandra (in other words, it’s the size of each page) default_fetch_size: "${CASSANDRA_DEFAULT_FETCH_SIZE:2000}" # Specify partitioning size for timestamp key-value storage. Example: MINUTES, HOURS, DAYS, MONTHS, INDEFINITE ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}" + # Enable/Disable timestamp key-value partioning on read queries use_ts_key_value_partitioning_on_read: "${USE_TS_KV_PARTITIONING_ON_READ:true}" + # The number of partitions that are cached in memory of each service. Useful to decrease load of re-inserting same partitions again ts_key_value_partitions_max_cache_size: "${TS_KV_PARTITIONS_MAX_CACHE_SIZE:100000}" + # Timeseries Time To Live (in seconds) for Cassandra Record. 0 - record is never expired ts_key_value_ttl: "${TS_KV_TTL:0}" + # Maximum number of Cassandra queries that are waiting for execution buffer_size: "${CASSANDRA_QUERY_BUFFER_SIZE:200000}" + # Maximum number of concurrent Cassandra queries concurrent_limit: "${CASSANDRA_QUERY_CONCURRENT_LIMIT:1000}" + # Max time in milliseconds query waits for execution permit_max_wait_time: "${PERMIT_MAX_WAIT_TIME:120000}" + # Amount of threads to dispatch cassandra queries dispatcher_threads: "${CASSANDRA_QUERY_DISPATCHER_THREADS:2}" callback_threads: "${CASSANDRA_QUERY_CALLBACK_THREADS:4}" # Buffered rate executor (read, write), for managing I/O rate. See "nosql-*-callback" threads in JMX result_processing_threads: "${CASSANDRA_QUERY_RESULT_PROCESSING_THREADS:50}" # Result set transformer and processing. See "cassandra-callback" threads in JMX + # Cassandra query queue polling interval in milliseconds poll_ms: "${CASSANDRA_QUERY_POLL_MS:50}" + # Interval in milliseconds for printing Cassandra query queue statistic rate_limit_print_interval_ms: "${CASSANDRA_QUERY_RATE_LIMIT_PRINT_MS:10000}" # set all data types values except target to null for the same ts on save set_null_values_enabled: "${CASSANDRA_QUERY_SET_NULL_VALUES_ENABLED:false}" # log one of cassandra queries with specified frequency (0 - logging is disabled) print_queries_freq: "${CASSANDRA_QUERY_PRINT_FREQ:0}" tenant_rate_limits: + # Whether to print rate-limited tenant names when printing Cassandra query queue statistic print_tenant_names: "${CASSANDRA_QUERY_TENANT_RATE_LIMITS_PRINT_TENANT_NAMES:false}" # SQL configuration parameters sql: # Specify batch size for persisting attribute updates attributes: - 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_size: "${SQL_ATTRIBUTES_BATCH_SIZE:10000}" # Batch size for persisting attribute updates + batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:100}" # Max timeout for attributes entries queue polling. Value set in milliseconds + stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing attributes updates statistic 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 - value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" + value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" # If true attribute values will be checked for XSS vulnerability 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_size: "${SQL_TS_BATCH_SIZE:10000}" # Batch size for persisting timeseries inserts + batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}" # Max timeout for time-series entries queue polling. Value set in milliseconds + stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing timeseries insert statistic 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 - value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" + value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" # If true telemetry values will be checked for XSS vulnerability 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_size: "${SQL_TS_LATEST_BATCH_SIZE:10000}" # Batch size for persisting latest telemetry updates + batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:100}" # Maximum timeout for latest telemetry entries queue polling. The value set in milliseconds + stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing latest telemetry updates statistic 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}" + update_by_latest_ts: "${SQL_TS_UPDATE_BY_LATEST_TIMESTAMP:true}" # Update latest values only if the timestamp of the new record is greater or equals than timestamp of the previously saved latest value. Latest values are stored separately from historical values for fast lookup from DB. Insert of historical value happens in any case events: - batch_size: "${SQL_EVENTS_BATCH_SIZE:10000}" - batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}" - stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}" + batch_size: "${SQL_EVENTS_BATCH_SIZE:10000}" # Batch size for persisting latest telemetry updates + batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}" # Max timeout for latest telemetry entries queue polling. The value set in milliseconds + stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing latest telemetry updates statistic batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution partition_size: "${SQL_EVENTS_REGULAR_PARTITION_SIZE_HOURS:168}" # Number of hours to partition the events. The current value corresponds to one week. debug_partition_size: "${SQL_EVENTS_DEBUG_PARTITION_SIZE_HOURS:1}" # Number of hours to partition the debug events. The current value corresponds to one hour. edge_events: - batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}" - batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}" - stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}" + batch_size: "${SQL_EDGE_EVENTS_BATCH_SIZE:1000}" # Batch size for persisting latest telemetry updates + batch_max_delay: "${SQL_EDGE_EVENTS_BATCH_MAX_DELAY_MS:100}" # Max timeout for latest telemetry entries queue polling. The value set in milliseconds + stats_print_interval_ms: "${SQL_EDGE_EVENTS_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing latest telemetry updates statistic partition_size: "${SQL_EDGE_EVENTS_PARTITION_SIZE_HOURS:168}" # Number of hours to partition the events. The current value corresponds to one week. audit_logs: partition_size: "${SQL_AUDIT_LOGS_PARTITION_SIZE_HOURS:168}" # Default value - 1 week @@ -309,8 +358,11 @@ sql: remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}" # Specify whether to log database queries and their parameters generated by entity query repository log_queries: "${SQL_LOG_QUERIES:false}" + # Threshold of slow SQL queries to log. The value set in milliseconds log_queries_threshold: "${SQL_LOG_QUERIES_THRESHOLD:5000}" + # Enable/Disable logging statistic information about tenants log_tenant_stats: "${SQL_LOG_TENANT_STATS:true}" + # Interval in milliseconds for printing latest statistic information about tenant log_tenant_stats_interval_ms: "${SQL_LOG_TENANT_STATS_INTERVAL_MS:60000}" postgres: # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE. @@ -321,10 +373,12 @@ sql: 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: + # The parameter to specify whether to use TTL (Time To Live) for timeseries records enabled: "${SQL_TTL_TS_ENABLED:true}" execution_interval_ms: "${SQL_TTL_TS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day ts_key_value_ttl: "${SQL_TTL_TS_TS_KEY_VALUE_TTL:0}" # Number of seconds events: + # The parameter to specify whether to use TTL (Time To Live) for event records enabled: "${SQL_TTL_EVENTS_ENABLED:true}" execution_interval_ms: "${SQL_TTL_EVENTS_EXECUTION_INTERVAL:3600000}" # Number of milliseconds (max random initial delay and fixed period). # Number of seconds. TTL is disabled by default. Accuracy of the cleanup depends on the sql.events.partition_size parameter. @@ -332,21 +386,21 @@ sql: # Number of seconds. The current value corresponds to one week. Accuracy of the cleanup depends on the sql.events.debug_partition_size parameter. debug_events_ttl: "${SQL_TTL_EVENTS_DEBUG_EVENTS_TTL:604800}" edge_events: - enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}" + enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for egde event records execution_interval_ms: "${SQL_TTL_EDGE_EVENTS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day edge_events_ttl: "${SQL_TTL_EDGE_EVENTS_TTL:2628000}" # Number of seconds. The current value corresponds to one month alarms: checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches rpc: - enabled: "${SQL_TTL_RPC_ENABLED:true}" + enabled: "${SQL_TTL_RPC_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for rpc call records checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours audit_logs: - enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" + enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for audit log records ttl: "${SQL_TTL_AUDIT_LOGS_SECS:0}" # Disabled by default. Accuracy of the cleanup depends on the sql.audit_logs.partition_size checking_interval_ms: "${SQL_TTL_AUDIT_LOGS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day notifications: - enabled: "${SQL_TTL_NOTIFICATIONS_ENABLED:true}" + enabled: "${SQL_TTL_NOTIFICATIONS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for notification center records ttl: "${SQL_TTL_NOTIFICATIONS_SECS:2592000}" # Default value - 30 days checking_interval_ms: "${SQL_TTL_NOTIFICATIONS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day relations: @@ -357,17 +411,17 @@ sql: # Actor system parameters actors: system: - throughput: "${ACTORS_SYSTEM_THROUGHPUT:5}" - scheduler_pool_size: "${ACTORS_SYSTEM_SCHEDULER_POOL_SIZE:1}" - max_actor_init_attempts: "${ACTORS_SYSTEM_MAX_ACTOR_INIT_ATTEMPTS:10}" - app_dispatcher_pool_size: "${ACTORS_SYSTEM_APP_DISPATCHER_POOL_SIZE:1}" - tenant_dispatcher_pool_size: "${ACTORS_SYSTEM_TENANT_DISPATCHER_POOL_SIZE:2}" - device_dispatcher_pool_size: "${ACTORS_SYSTEM_DEVICE_DISPATCHER_POOL_SIZE:4}" - rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:4}" + throughput: "${ACTORS_SYSTEM_THROUGHPUT:5}" # Number of messages the actor system will process per actor before switching to processing of messages for next actor + scheduler_pool_size: "${ACTORS_SYSTEM_SCHEDULER_POOL_SIZE:1}" # Thread pool size for actor system scheduler + max_actor_init_attempts: "${ACTORS_SYSTEM_MAX_ACTOR_INIT_ATTEMPTS:10}" # Maximum number of attempts to init the actor before disabling the actor + app_dispatcher_pool_size: "${ACTORS_SYSTEM_APP_DISPATCHER_POOL_SIZE:1}" # Thread pool size for main actor system dispatcher + tenant_dispatcher_pool_size: "${ACTORS_SYSTEM_TENANT_DISPATCHER_POOL_SIZE:2}" # Thread pool size for actor system dispatcher that process messages for tenant actors + device_dispatcher_pool_size: "${ACTORS_SYSTEM_DEVICE_DISPATCHER_POOL_SIZE:4}" # Thread pool size for actor system dispatcher that process messages for device actors + rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:4}" # Thread pool size for actor system dispatcher that process messages for rule engine (chain/node) actors tenant: - create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" + create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" # Create components in initialization session: - max_concurrent_sessions_per_device: "${ACTORS_MAX_CONCURRENT_SESSION_PER_DEVICE:1}" + max_concurrent_sessions_per_device: "${ACTORS_MAX_CONCURRENT_SESSION_PER_DEVICE:1}" # Max number of concurrent sessions per device sync: # Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}" @@ -390,7 +444,9 @@ actors: # Errors for particular actor are persisted once per specified amount of milliseconds error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" debug_mode_rate_limits_per_tenant: + # Enable/Disable the rate limit of persisted debug events for all rule nodes per tenant enabled: "${ACTORS_RULE_CHAIN_DEBUG_MODE_RATE_LIMITS_PER_TENANT_ENABLED:true}" + # The value of DEBUG mode rate limit. By default, no more then 50 thousand events per hour configuration: "${ACTORS_RULE_CHAIN_DEBUG_MODE_RATE_LIMITS_PER_TENANT_CONFIGURATION:50000:3600}" node: # Errors for particular actor are persisted once per specified amount of milliseconds @@ -414,9 +470,12 @@ actors: statistics: # Enable/disable actor statistics enabled: "${ACTORS_STATISTICS_ENABLED:true}" + # Frequency of printing the JS executor statistics js_print_interval_ms: "${ACTORS_JS_STATISTICS_PRINT_INTERVAL_MS:10000}" + # Actors statistic persistence frequency in milliseconds persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}" +# Cache parameters cache: # caffeine or redis type: "${CACHE_TYPE:caffeine}" @@ -426,113 +485,118 @@ cache: enabled: "${CACHE_ATTRIBUTES_ENABLED:true}" specs: relations: - timeToLiveInMinutes: "${CACHE_SPECS_RELATIONS_TTL:1440}" - maxSize: "${CACHE_SPECS_RELATIONS_MAX_SIZE:10000}" # maxSize: 0 means the cache is disabled + timeToLiveInMinutes: "${CACHE_SPECS_RELATIONS_TTL:1440}" # Relations cache max size + maxSize: "${CACHE_SPECS_RELATIONS_MAX_SIZE:10000}" # 0 means the cache is disabled deviceCredentials: - timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_CREDENTIALS_TTL:1440}" - maxSize: "${CACHE_SPECS_DEVICE_CREDENTIALS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_CREDENTIALS_TTL:1440}" # Device credentials cache TTL + maxSize: "${CACHE_SPECS_DEVICE_CREDENTIALS_MAX_SIZE:10000}" # 0 means the cache is disabled devices: - timeToLiveInMinutes: "${CACHE_SPECS_DEVICES_TTL:1440}" - maxSize: "${CACHE_SPECS_DEVICES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_DEVICES_TTL:1440}" # Device cache TTL + maxSize: "${CACHE_SPECS_DEVICES_MAX_SIZE:10000}" # 0 means the cache is disabled sessions: - timeToLiveInMinutes: "${CACHE_SPECS_SESSIONS_TTL:1440}" - maxSize: "${CACHE_SPECS_SESSIONS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_SESSIONS_TTL:1440}" # Sessions cache TTL + maxSize: "${CACHE_SPECS_SESSIONS_MAX_SIZE:10000}" # 0 means the cache is disabled assets: - timeToLiveInMinutes: "${CACHE_SPECS_ASSETS_TTL:1440}" - maxSize: "${CACHE_SPECS_ASSETS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_ASSETS_TTL:1440}" # Asset cache TTL + maxSize: "${CACHE_SPECS_ASSETS_MAX_SIZE:10000}" # 0 means the cache is disabled entityViews: - timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_VIEWS_TTL:1440}" - maxSize: "${CACHE_SPECS_ENTITY_VIEWS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_VIEWS_TTL:1440}" # Entity view cache TTL + maxSize: "${CACHE_SPECS_ENTITY_VIEWS_MAX_SIZE:10000}" # 0 means the cache is disabled claimDevices: - timeToLiveInMinutes: "${CACHE_SPECS_CLAIM_DEVICES_TTL:1440}" - maxSize: "${CACHE_SPECS_CLAIM_DEVICES_MAX_SIZE:1000}" + timeToLiveInMinutes: "${CACHE_SPECS_CLAIM_DEVICES_TTL:1440}" # Claim devices cache TTL + maxSize: "${CACHE_SPECS_CLAIM_DEVICES_MAX_SIZE:1000}" # 0 means the cache is disabled securitySettings: - timeToLiveInMinutes: "${CACHE_SPECS_SECURITY_SETTINGS_TTL:1440}" - maxSize: "${CACHE_SPECS_SECURITY_SETTINGS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_SECURITY_SETTINGS_TTL:1440}" # Security settings cache TTL + maxSize: "${CACHE_SPECS_SECURITY_SETTINGS_MAX_SIZE:10000}" # 0 means the cache is disabled tenantProfiles: - timeToLiveInMinutes: "${CACHE_SPECS_TENANT_PROFILES_TTL:1440}" - maxSize: "${CACHE_SPECS_TENANT_PROFILES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_TENANT_PROFILES_TTL:1440}" # Tenant profiles cache TTL + maxSize: "${CACHE_SPECS_TENANT_PROFILES_MAX_SIZE:10000}" # 0 means the cache is disabled tenants: - timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" - maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" # Tenant cache TTL + maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" # 0 means the cache is disabled tenantsExist: # environment variables are intentionally the same as in 'tenants' cache to be equal. timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" - maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" + maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" # 0 means the cache is disabled deviceProfiles: - timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_PROFILES_TTL:1440}" - maxSize: "${CACHE_SPECS_DEVICE_PROFILES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_PROFILES_TTL:1440}" # Device profile cache TTL + maxSize: "${CACHE_SPECS_DEVICE_PROFILES_MAX_SIZE:10000}" # 0 means the cache is disabled assetProfiles: - timeToLiveInMinutes: "${CACHE_SPECS_ASSET_PROFILES_TTL:1440}" - maxSize: "${CACHE_SPECS_ASSET_PROFILES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_ASSET_PROFILES_TTL:1440}" # Asset profile cache TTL + maxSize: "${CACHE_SPECS_ASSET_PROFILES_MAX_SIZE:10000}" # 0 means the cache is disabled notificationSettings: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}" - maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}" + timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}" # Noification settings cache TTL + maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}" # 0 means the cache is disabled sentNotifications: - timeToLiveInMinutes: "${CACHE_SPECS_SENT_NOTIFICATIONS_TTL:1440}" - maxSize: "${CACHE_SPECS_SENT_NOTIFICATIONS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_SENT_NOTIFICATIONS_TTL:1440}" # Sent notifications cache TTL + maxSize: "${CACHE_SPECS_SENT_NOTIFICATIONS_MAX_SIZE:10000}" # 0 means the cache is disabled attributes: - timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" - maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" # Attributes cache TTL + maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" # 0 means the cache is disabled userSessionsInvalidation: # The value of this TTL is ignored and replaced by JWT refresh token expiration time timeToLiveInMinutes: "0" - maxSize: "${CACHE_SPECS_USERS_UPDATE_TIME_MAX_SIZE:10000}" + maxSize: "${CACHE_SPECS_USERS_UPDATE_TIME_MAX_SIZE:10000}" # 0 means the cache is disabled otaPackages: - timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_TTL:60}" - maxSize: "${CACHE_SPECS_OTA_PACKAGES_MAX_SIZE:10}" + timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_TTL:60}" # Ota packages cache TTL + maxSize: "${CACHE_SPECS_OTA_PACKAGES_MAX_SIZE:10}" # 0 means the cache is disabled otaPackagesData: - timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_DATA_TTL:60}" - maxSize: "${CACHE_SPECS_OTA_PACKAGES_DATA_MAX_SIZE:10}" + timeToLiveInMinutes: "${CACHE_SPECS_OTA_PACKAGES_DATA_TTL:60}" # Ota packages data cache TTL + maxSize: "${CACHE_SPECS_OTA_PACKAGES_DATA_MAX_SIZE:10}" # 0 means the cache is disabled edges: - timeToLiveInMinutes: "${CACHE_SPECS_EDGES_TTL:1440}" - maxSize: "${CACHE_SPECS_EDGES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_EDGES_TTL:1440}" # Edges cache TTL + maxSize: "${CACHE_SPECS_EDGES_MAX_SIZE:10000}" # 0 means the cache is disabled repositorySettings: - timeToLiveInMinutes: "${CACHE_SPECS_REPOSITORY_SETTINGS_TTL:1440}" - maxSize: "${CACHE_SPECS_REPOSITORY_SETTINGS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_REPOSITORY_SETTINGS_TTL:1440}" # Repository settings cache TTL + maxSize: "${CACHE_SPECS_REPOSITORY_SETTINGS_MAX_SIZE:10000}" # 0 means the cache is disabled autoCommitSettings: - timeToLiveInMinutes: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_TTL:1440}" - maxSize: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_TTL:1440}" # Autocommit settings cache TTL + maxSize: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_MAX_SIZE:10000}" # 0 means the cache is disabled twoFaVerificationCodes: - timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}" - maxSize: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}" # Two fa carification codes cache TTL + maxSize: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_MAX_SIZE:100000}" # 0 means the cache is disabled versionControlTask: - timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:20}" - maxSize: "${CACHE_SPECS_VERSION_CONTROL_TASK_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:20}" # Version control task cache TTL + maxSize: "${CACHE_SPECS_VERSION_CONTROL_TASK_MAX_SIZE:100000}" # 0 means the cache is disabled userSettings: - timeToLiveInMinutes: "${CACHE_SPECS_USER_SETTINGS_TTL:1440}" - maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_USER_SETTINGS_TTL:1440}" # User settings cache TTL + maxSize: "${CACHE_SPECS_USER_SETTINGS_MAX_SIZE:100000}" # 0 means the cache is disabled dashboardTitles: - timeToLiveInMinutes: "${CACHE_SPECS_DASHBOARD_TITLES_TTL:1440}" - maxSize: "${CACHE_SPECS_DASHBOARD_TITLES_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_DASHBOARD_TITLES_TTL:1440}" # Dashboard titles cache TTL + maxSize: "${CACHE_SPECS_DASHBOARD_TITLES_MAX_SIZE:100000}" # 0 means the cache is disabled entityCount: - timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}" - maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_ENTITY_COUNT_TTL:1440}" # Entity count cache TTL + maxSize: "${CACHE_SPECS_ENTITY_COUNT_MAX_SIZE:100000}" # 0 means the cache is disabled resourceInfo: - timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" - maxSize: "${CACHE_SPECS_RESOURCE_INFO_MAX_SIZE:100000}" + timeToLiveInMinutes: "${CACHE_SPECS_RESOURCE_INFO_TTL:1440}" # Resource info cache TTL + maxSize: "${CACHE_SPECS_RESOURCE_INFO_MAX_SIZE:100000}" # 0 means the cache is disabled alarmTypes: - timeToLiveInMinutes: "${CACHE_SPECS_ALARM_TYPES_TTL:60}" - maxSize: "${CACHE_SPECS_ALARM_TYPES_MAX_SIZE:10000}" + timeToLiveInMinutes: "${CACHE_SPECS_ALARM_TYPES_TTL:60}" # Alarm types cache TTL + maxSize: "${CACHE_SPECS_ALARM_TYPES_MAX_SIZE:10000}" # 0 means the cache is disabled # deliberately placed outside 'specs' group above notificationRules: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}" - maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:1000}" + timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}" # notification rules cache TTL + maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:1000}" # 0 means the cache is disabled rateLimits: - timeToLiveInMinutes: "${CACHE_SPECS_RATE_LIMITS_TTL:120}" - maxSize: "${CACHE_SPECS_RATE_LIMITS_MAX_SIZE:200000}" + timeToLiveInMinutes: "${CACHE_SPECS_RATE_LIMITS_TTL:120}" # Rate limits cache TTL + maxSize: "${CACHE_SPECS_RATE_LIMITS_MAX_SIZE:200000}" # 0 means the cache is disabled -#Disable this because it is not required. -spring.data.redis.repositories.enabled: false +# Spring data properties +spring.data.redis.repositories.enabled: false # Disable this because it is not required. +# Redis configuration properties redis: # standalone or cluster or sentinel connection: + # Redis deployment type: Standalone (single Redis node deployment) OR Cluster type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -564,31 +628,37 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" # TTL for short-living SET commands that are used to replace DEL in order to enable transaction support evictTtlInMs: "${REDIS_EVICT_TTL_MS:60000}" -# Check new version updates parameters +# Update version properties updates: - # Enable/disable updates checking. + # Enable/disable checks for new version enabled: "${UPDATES_ENABLED:true}" -spring.main.allow-circular-references: "true" - -# spring freemarker configuration -spring.freemarker.checkTemplateLocation: "false" - -# spring CORS configuration +# Spring CORS configuration spring.mvc.cors: mappings: # Intercept path @@ -604,45 +674,49 @@ spring.mvc.cors: #Set whether credentials are supported. When not set, credentials are not supported. allow-credentials: "true" -# The default timeout for asynchronous requests in milliseconds -spring.mvc.async.request-timeout: "${SPRING_MVC_ASYNC_REQUEST_TIMEOUT:30000}" - -# For endpoints matching in Swagger -spring.mvc.pathmatch.matching-strategy: "ANT_PATH_MATCHER" - -# spring serve gzip compressed static resources +# General spring properties +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed or not. +spring.freemarker.checkTemplateLocation: "false" # spring freemarker configuration +spring.mvc.async.request-timeout: "${SPRING_MVC_ASYNC_REQUEST_TIMEOUT:30000}" # The default timeout for asynchronous requests in milliseconds +spring.mvc.pathmatch.matching-strategy: "ANT_PATH_MATCHER" # For endpoints matching in Swagger spring.resources.chain: - compressed: "true" + compressed: "true" # This property enables or disables support for serving pre-compressed resources (for example, a .gzip or .br file) strategy: content: - enabled: "true" + enabled: "true" # This property enables or disables the content Version Strategy. This strategy allows Spring to generate a unique version for static resources, which is based on the content of the resource -spring.servlet.multipart.max-file-size: "50MB" -spring.servlet.multipart.max-request-size: "50MB" +spring.servlet.multipart.max-file-size: "50MB" # Total file size cannot exceed 50MB when configuring file uploads +spring.servlet.multipart.max-request-size: "50MB" # Total request size for a multipart/form-data cannot exceed 50MB -spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" -# Note: as for current Spring JPA version, custom NullHandling for the Sort.Order is ignored and this parameter is used -spring.jpa.properties.hibernate.order_by.default_null_ordering: "${SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING:last}" +spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" #Fix Postgres JPA Error (Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented) +spring.jpa.properties.hibernate.order_by.default_null_ordering: "${SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING:last}" # Note: as for current Spring JPA version, custom NullHandling for the Sort.Order is ignored and this parameter is used # SQL DAO Configuration spring: data: jpa: repositories: - enabled: "true" + enabled: "true" # Enable/Disable the Spring Data JPA repositories support jpa: properties: - javax.persistence.query.timeout: "${JAVAX_PERSISTENCE_QUERY_TIMEOUT:30000}" - open-in-view: "false" + javax.persistence.query.timeout: "${JAVAX_PERSISTENCE_QUERY_TIMEOUT:30000}" # General timeout for JDBC queries + open-in-view: "false" # Enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning hibernate: + # You can set a Hibernate feature that controls the DDL behavior in a more fine-grained way. The standard Hibernate property values are none, validate, update, create-drop. Spring Boot chooses a default value for you based on whether it thinks your database is embedded (default create-drop) or not (default none) ddl-auto: "none" datasource: + # Database driver for Spring JPA - org.postgresql.Driver driverClassName: "${SPRING_DRIVER_CLASS_NAME:org.postgresql.Driver}" + # Database connection URL url: "${SPRING_DATASOURCE_URL:jdbc:postgresql://localhost:5432/thingsboard}" + # Database user name username: "${SPRING_DATASOURCE_USERNAME:postgres}" + # Database user password password: "${SPRING_DATASOURCE_PASSWORD:postgres}" hikari: + # This property controls the amount of time that a connection can be out of the pool before a message is logged indicating a possible connection leak. A value of 0 means leak detection is disabled leakDetectionThreshold: "${SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD:0}" + # This property allows the number of connections in the pool to increase as demand increases. At the same time, the property ensures that the pool doesn't grow to the point of exhausting a system's resources, which ultimately affects an application's performance and availability maximumPoolSize: "${SPRING_DATASOURCE_MAXIMUM_POOL_SIZE:16}" registerMbeans: "${SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS:false}" # true - enable MBean to diagnose pools state via JMX @@ -654,21 +728,21 @@ audit-log: # Allowed values: OFF (disable), W (log write operations), RW (log read and write operations) logging-level: mask: - "device": "${AUDIT_LOG_MASK_DEVICE:W}" - "asset": "${AUDIT_LOG_MASK_ASSET:W}" - "dashboard": "${AUDIT_LOG_MASK_DASHBOARD:W}" - "widget_type": "${AUDIT_LOG_MASK_WIDGET_TYPE:W}" - "widgets_bundle": "${AUDIT_LOG_MASK_WIDGETS_BUNDLE:W}" - "customer": "${AUDIT_LOG_MASK_CUSTOMER:W}" - "user": "${AUDIT_LOG_MASK_USER:W}" - "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" - "alarm": "${AUDIT_LOG_MASK_ALARM:W}" - "entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}" - "device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}" - "asset_profile": "${AUDIT_LOG_MASK_ASSET_PROFILE:W}" - "edge": "${AUDIT_LOG_MASK_EDGE:W}" - "tb_resource": "${AUDIT_LOG_MASK_RESOURCE:W}" - "ota_package": "${AUDIT_LOG_MASK_OTA_PACKAGE:W}" + "device": "${AUDIT_LOG_MASK_DEVICE:W}" # Device logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "asset": "${AUDIT_LOG_MASK_ASSET:W}" # Asset logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "dashboard": "${AUDIT_LOG_MASK_DASHBOARD:W}" # Dashboard logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "widget_type": "${AUDIT_LOG_MASK_WIDGET_TYPE:W}" # Widget type logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "widgets_bundle": "${AUDIT_LOG_MASK_WIDGETS_BUNDLE:W}" # Widget bundles logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "customer": "${AUDIT_LOG_MASK_CUSTOMER:W}" # Customer logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "user": "${AUDIT_LOG_MASK_USER:W}" # User logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "rule_chain": "${AUDIT_LOG_MASK_RULE_CHAIN:W}" # Rule chain logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "alarm": "${AUDIT_LOG_MASK_ALARM:W}" # Alarm logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "entity_view": "${AUDIT_LOG_MASK_ENTITY_VIEW:W}" # Entity view logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "device_profile": "${AUDIT_LOG_MASK_DEVICE_PROFILE:W}" # Device profile logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "asset_profile": "${AUDIT_LOG_MASK_ASSET_PROFILE:W}" # Asset profile logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "edge": "${AUDIT_LOG_MASK_EDGE:W}" # Edge logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "tb_resource": "${AUDIT_LOG_MASK_RESOURCE:W}" # TB resource logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation + "ota_package": "${AUDIT_LOG_MASK_OTA_PACKAGE:W}" # Ota package logging levels. Allowed values: OFF (disable), W (log write operations), RW (log read and write operation sink: # Type of external sink. possible options: none, elasticsearch type: "${AUDIT_LOG_SINK_TYPE:none}" @@ -681,25 +755,31 @@ audit-log: # https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html date_format: "${AUDIT_LOG_SINK_DATE_FORMAT:YYYY.MM.dd}" scheme_name: "${AUDIT_LOG_SINK_SCHEME_NAME:http}" # http or https - host: "${AUDIT_LOG_SINK_HOST:localhost}" - port: "${AUDIT_LOG_SINK_PORT:9200}" - user_name: "${AUDIT_LOG_SINK_USER_NAME:}" - password: "${AUDIT_LOG_SINK_PASSWORD:}" + host: "${AUDIT_LOG_SINK_HOST:localhost}" # Host of external sink system + port: "${AUDIT_LOG_SINK_PORT:9200}" # Port of external sink system + user_name: "${AUDIT_LOG_SINK_USER_NAME:}" # Username used to access external sink system + password: "${AUDIT_LOG_SINK_PASSWORD:}" # Password used to access external sink system +# State properties state: - # Should be greater then transport.sessions.report_timeout + # Should be greater than transport.sessions.report_timeout defaultInactivityTimeoutInSec: "${DEFAULT_INACTIVITY_TIMEOUT:600}" - defaultStateCheckIntervalInSec: "${DEFAULT_STATE_CHECK_INTERVAL:60}" + defaultStateCheckIntervalInSec: "${DEFAULT_STATE_CHECK_INTERVAL:60}" # Interval for checking the device state after a specified period of time. Time in seconds # Controls whether we store device 'active' flag in attributes (default) or telemetry. # If you device to change this parameter, you should re-create the device info view as one of the following: # If 'persistToTelemetry' is changed from 'false' to 'true': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_ts_view;' # If 'persistToTelemetry' is changed from 'true' to 'false': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view;' persistToTelemetry: "${PERSIST_STATE_TO_TELEMETRY:false}" +# Tbel properties tbel: + # Enable/Disable TBEL feature. enabled: "${TBEL_ENABLED:true}" + # Limit on the number of arguments that are passed to the function to execute the script max_total_args_size: "${TBEL_MAX_TOTAL_ARGS_SIZE:100000}" + # Maximum allowed symbols in a result after processing a script max_result_size: "${TBEL_MAX_RESULT_SIZE:300000}" + # Maximum allowed symbols in script body max_script_body_size: "${TBEL_MAX_SCRIPT_BODY_SIZE:50000}" # Maximum allowed TBEL script execution memory max_memory_limit_mb: "${TBEL_MAX_MEMORY_LIMIT_MB: 8}" @@ -711,15 +791,23 @@ tbel: max_black_list_duration_sec: "${TBEL_MAX_BLACKLIST_DURATION_SEC:60}" # Specify thread pool size for javascript executor service thread_pool_size: "${TBEL_THREAD_POOL_SIZE:50}" + # Maximum cache size of TBEL compiled scripts compiled_scripts_cache_size: "${TBEL_COMPILED_SCRIPTS_CACHE_SIZE:1000}" stats: + # Enable/Disable stats collection for TBEL engine enabled: "${TB_TBEL_STATS_ENABLED:false}" + # Interval of logging for TBEL stats print_interval_ms: "${TB_TBEL_STATS_PRINT_INTERVAL_MS:10000}" +# JS properties js: - evaluator: "${JS_EVALUATOR:local}" # local/remote + # local (Nashorn Engine, deprecated) OR remote JS-Executors (NodeJS) + evaluator: "${JS_EVALUATOR:local}" + # Limit on the number of arguments that are passed to the function to execute the script max_total_args_size: "${JS_MAX_TOTAL_ARGS_SIZE:100000}" + # Maximum allowed symbols in a result after processing a script max_result_size: "${JS_MAX_RESULT_SIZE:300000}" + # Maximum allowed symbols in script body max_script_body_size: "${JS_MAX_SCRIPT_BODY_SIZE:50000}" # Built-in JVM JavaScript environment properties local: @@ -738,7 +826,9 @@ js: # Maximum time in seconds for black listed function to stay in the list. max_black_list_duration_sec: "${LOCAL_JS_SANDBOX_MAX_BLACKLIST_DURATION_SEC:60}" stats: + # Enable/Disable stats collection for local JS executor enabled: "${TB_JS_LOCAL_STATS_ENABLED:false}" + # Interval of logging for local JS executor stats print_interval_ms: "${TB_JS_LOCAL_STATS_PRINT_INTERVAL_MS:10000}" # Remote JavaScript environment properties remote: @@ -749,12 +839,17 @@ js: # 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: + # Enable/Disable stats collection for remote JS executor enabled: "${TB_JS_REMOTE_STATS_ENABLED:false}" + # Interval of logging for remote JS executor stats print_interval_ms: "${TB_JS_REMOTE_STATS_PRINT_INTERVAL_MS:10000}" +# Transport configuration properties transport: sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -762,11 +857,14 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" client_side_rpc: + # Processing timeout interval of the RPC command on the CLIENT SIDE. Time in milliseconds 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}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" rate_limits: # Enable or disable generic rate limits. Device and Tenant specific rate limits are controlled in Tenant Profile. @@ -777,25 +875,36 @@ transport: ip_block_timeout: "${TB_TRANSPORT_IP_BLOCK_TIMEOUT:60000}" # Local HTTP transport parameters http: + # Enable/Disable local HTTP transport protocol enabled: "${HTTP_ENABLED:true}" + # HTTP request processing timeout in milliseconds request_timeout: "${HTTP_REQUEST_TIMEOUT:60000}" + # HTTP maximum request processing timeout in milliseconds max_request_timeout: "${HTTP_MAX_REQUEST_TIMEOUT:300000}" # Local MQTT transport parameters mqtt: # Enable/disable mqtt transport protocol. enabled: "${MQTT_ENABLED:true}" + # MQTT bind address bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" + # MQTT bind port bind_port: "${MQTT_BIND_PORT:1883}" # Enable proxy protocol support. Disabled by default. If enabled, supports both v1 and v2. # Useful to get the real IP address of the client in the logs and for rate limits. proxy_enabled: "${MQTT_PROXY_PROTOCOL_ENABLED:false}" + # MQTT processing timeout in milliseconds timeout: "${MQTT_TIMEOUT:10000}" msg_queue_size_per_device_limit: "${MQTT_MSG_QUEUE_SIZE_PER_DEVICE_LIMIT:100}" # messages await in the queue before device connected state. This limit works on low level before TenantProfileLimits mechanism netty: + # Netty leak detector level leak_detector_level: "${NETTY_LEAK_DETECTOR_LVL:DISABLED}" + # Netty BOSS threads count boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" + # Netty worker threads count worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" + # Max payload size in bytes max_payload_size: "${NETTY_MAX_PAYLOAD_SIZE:65536}" + # Enables TCP keepalive. This means that TCP starts sending keepalive probes when a connection is idle for some time so_keep_alive: "${NETTY_SO_KEEPALIVE:false}" # MQTT SSL configuration ssl: @@ -837,11 +946,17 @@ transport: coap: # Enable/disable coap transport protocol. enabled: "${COAP_ENABLED:true}" + # CoAP bind address bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" + # CoAP bind port bind_port: "${COAP_BIND_PORT:5683}" + # CoaP processing timeout in milliseconds timeout: "${COAP_TIMEOUT:10000}" + # CoaP piggyback response timeout in milliseconds piggyback_timeout: "${COAP_PIGGYBACK_TIMEOUT:500}" + # Default PSM Activity Timer if not specified in device profile psm_activity_timer: "${COAP_PSM_ACTIVITY_TIMER:10000}" + # Default PSM Activity Timer if not specified in device profile paging_transmission_window: "${COAP_PAGING_TRANSMISSION_WINDOW:10000}" dtls: # Enable/disable DTLS 1.2 support @@ -879,7 +994,9 @@ transport: x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" + # Inactivity timeout of DTLS session. Used to cleanup cache dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" + # Interval of periodic eviction of the timed-out DTLS sessions dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" # Local LwM2M transport parameters lwm2m: @@ -889,11 +1006,16 @@ transport: # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 retransmission_timeout: "${LWM2M_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" server: + # LwM2M Server ID id: "${LWM2M_SERVER_ID:123}" + # LwM2M server bind address. Bind to all interfaces by default bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + # LwM2M server bind port bind_port: "${LWM2M_BIND_PORT:5685}" security: + # LwM2M server bind address for DTLS. Bind to all interfaces by default bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" + # LwM2M server bind port for DTLS bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" # Server X509 Certificates support credentials: @@ -924,12 +1046,18 @@ transport: # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: + # Enable/disable Bootstrap Server enabled: "${LWM2M_ENABLED_BS:true}" + # Default value in Lwm2mClient after start in mode Bootstrap for the object : name "LWM2M Security" field: "Short Server ID" (deviceProfile: Bootstrap.BOOTSTRAP SERVER.Short ID) id: "${LWM2M_SERVER_ID_BS:111}" + # LwM2M bootstrap server bind address. Bind to all interfaces by default bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" + # LwM2M bootstrap server bind port bind_port: "${LWM2M_BS_BIND_PORT:5687}" security: + # LwM2M bootstrap server bind address for DTLS. Bind to all interfaces by default bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" + # LwM2M bootstrap server bind address for DTLS. Bind to all interfaces by default bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" # Bootstrap server X509 Certificates support credentials: @@ -976,103 +1104,167 @@ transport: 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}" + # Set usage of recommended cipher suites; true - allow only recommended cipher suites; false - allow not recommended cipher suites recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" + # Set usage of recommended supported groups (curves); true - allow only recommended supported groups, false - allow not recommended supported groups recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" + # Timeout of LwM2M operation timeout: "${LWM2M_TIMEOUT:120000}" + # Thread pool size for processing of the LwM2M uplinks uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}" + # Thread pool size for processing of the LwM2M downlinks downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" + # Thread pool size for processing of the OTA updates ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" + # Period of cleanup for the registrations in store clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" + # Maximum log size log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" + # PSM Activity Timer if not specified in device profile psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" + # Paging Transmission Window for eDRX support if not specified in the device profile paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" 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: + # Enable/disable SNMP transport protocol enabled: "${SNMP_ENABLED:true}" + # Snmp bind port bind_port: "${SNMP_BIND_PORT:1620}" response_processing: # parallelism level for executor (workStealingPool) that is responsible for handling responses from SNMP devices parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}" # to configure SNMP to work over UDP or TCP underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}" + # Batch size to request OID mappings from device (useful when device profile has multiple hundreds of OID mappings) max_request_oids: "${SNMP_MAX_REQUEST_OIDS:100}" response: + # To ignore SNMP response values that do not match data type of the configured OID mapping (by default false - will throw error if any value of the response not matches configured data types) ignore_type_cast_errors: "${SNMP_RESPONSE_IGNORE_TYPE_CAST_ERRORS:false}" stats: + # Enable/Disable collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" # Device connectivity properties to publish telemetry device: connectivity: http: + # If true check-connectivity service will include curl command to the list of all test commands using DEVICE_CONNECTIVITY_HTTP_HOST and DEVICE_CONNECTIVITY_HTTP_PORT variables enabled: "${DEVICE_CONNECTIVITY_HTTP_ENABLED:true}" + # Host of http transport service. If empty base url will be used. host: "${DEVICE_CONNECTIVITY_HTTP_HOST:}" + # Port of http transport service. If empty default http port will be used. port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" https: + # If true check-connectivity service will include curl command to the list of all test commands using DEVICE_CONNECTIVITY_HTTPS_HOST and DEVICE_CONNECTIVITY_HTTPS_PORT variables enabled: "${DEVICE_CONNECTIVITY_HTTPS_ENABLED:false}" + # Host of http transport service. If empty base url will be used. host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:}" + # Port of http transport service. If empty default https port will be used. port: "${DEVICE_CONNECTIVITY_HTTPS_PORT:443}" mqtt: + # If true mosquito command will be included to the list of all test commands using DEVICE_CONNECTIVITY_MQTT_HOST and DEVICE_CONNECTIVITY_MQTT_PORT enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}" + # Host of mqtt transport service. If empty base url host will be used. host: "${DEVICE_CONNECTIVITY_MQTT_HOST:}" + # Port of mqtt transport service port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" mqtts: + # If true mosquito command will be included to the list of all test commands using DEVICE_CONNECTIVITY_MQTTS_HOST and DEVICE_CONNECTIVITY_MQTTS_PORT< enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}" + # Host of mqtt transport service. If empty base url host will be used. host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" + # Port of mqtt transport service. If empty default port for mqtts will be used. port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" + # Path to the server certificate file pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:mqttserver.pem}" coap: + # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" + # Host of coap transport service. If empty base url host will be used. host: "${DEVICE_CONNECTIVITY_COAP_HOST:}" + # Port of coap transport service. If empty default port for coap will be used. port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}" coaps: + # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAPS_HOST and DEVICE_CONNECTIVITY_COAPS_PORT. enabled: "${DEVICE_CONNECTIVITY_COAPS_ENABLED:false}" + # Host of coap transport service. If empty base url host will be used. host: "${DEVICE_CONNECTIVITY_COAPS_HOST:}" + # Port of coap transport service. If empty default port for coaps will be used. port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}" # Edges parameters edges: + # Enable/disable Edge instance enabled: "${EDGES_ENABLED:true}" rpc: + # RPC port bind port: "${EDGES_RPC_PORT:7070}" + # Maximum time of keep alive client RPC connection. Time in seconds client_max_keep_alive_time_sec: "${EDGES_RPC_CLIENT_MAX_KEEP_ALIVE_TIME_SEC:1}" + # Maximum time of keep alive connection. Time in seconds keep_alive_time_sec: "${EDGES_RPC_KEEP_ALIVE_TIME_SEC:10}" + # Timeout of keep alive RPC connection. Time in seconds keep_alive_timeout_sec: "${EDGES_RPC_KEEP_ALIVE_TIMEOUT_SEC:5}" ssl: # Enable/disable SSL support enabled: "${EDGES_RPC_SSL_ENABLED:false}" + # Cert file to be used during TLS connectivity to cloud cert: "${EDGES_RPC_SSL_CERT:certChainFile.pem}" + # Private key file associated with the Cert certificate. This key is used in the encryption process during a secure connection private_key: "${EDGES_RPC_SSL_PRIVATE_KEY:privateKeyFile.pem}" + # Maximum size (in bytes) of inbound messages that cloud can handle from edge. By default, it can handle messages up to 4 Megabytes max_inbound_message_size: "${EDGES_RPC_MAX_INBOUND_MESSAGE_SIZE:4194304}" storage: + # Max records of edge event to read from DB and sent to edge max_read_records_count: "${EDGES_STORAGE_MAX_READ_RECORDS_COUNT:50}" + # Number of milliseconds to wait before next check of edge events in DB no_read_records_sleep: "${EDGES_NO_READ_RECORDS_SLEEP:1000}" + # Number of milliseconds to wait before resend failed batch of edge events to edge sleep_between_batches: "${EDGES_SLEEP_BETWEEN_BATCHES:10000}" + # Number of threads that used to check DB for edge events scheduler_pool_size: "${EDGES_SCHEDULER_POOL_SIZE:1}" + # Number of threads that used to send downlink messages to edge over gRPC send_scheduler_pool_size: "${EDGES_SEND_SCHEDULER_POOL_SIZE:1}" + # Number of threads that used to convert edge events from DB into downlink message and send them for delivery grpc_callback_thread_pool_size: "${EDGES_GRPC_CALLBACK_POOL_SIZE:1}" state: + # Persist state of edge (active, last connect, last disconnect) into timeseries or attributes tables. 'false' means to store edge state into attributes table persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}" +# Swagger common properties swagger: + # If false swagger api docs will be unavailable enabled: "${SWAGGER_ENABLED:true}" + # General swagger match pattern of swaggerUI links api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/.*}" + # General swagger match pattern path of swaggerUI links security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}" + # Non security API path match pattern of swaggerUI links non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}" + # The title on the API doc UI page title: "${SWAGGER_TITLE:ThingsBoard REST API}" + # The description on the API doc UI page description: "${SWAGGER_DESCRIPTION: ThingsBoard open-source IoT platform REST API documentation.}" contact: + # The contact name on the API doc UI page name: "${SWAGGER_CONTACT_NAME:ThingsBoard team}" + # The contact URL on the API doc UI page url: "${SWAGGER_CONTACT_URL:https://thingsboard.io}" + # The contact email on the API doc UI page email: "${SWAGGER_CONTACT_EMAIL:info@thingsboard.io}" license: + # The license title on the API doc UI page title: "${SWAGGER_LICENSE_TITLE:Apache License Version 2.0}" + # Link to the license body on the API doc UI page url: "${SWAGGER_LICENSE_URL:https://github.com/thingsboard/thingsboard/blob/master/LICENSE}" + # The version of the API doc to display. Default to the package version. version: "${SWAGGER_VERSION:}" +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) in_memory: @@ -1080,44 +1272,73 @@ queue: # For debug lvl print-interval-ms: "${TB_QUEUE_IN_MEMORY_STATS_PRINT_INTERVAL_MS:60000}" kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for client and can be used for two-way authentication for client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" + # The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values none or gzip compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server host name. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" # Key-value properties for Kafka consumer per specific topic, e.g. tb_ota_package is a topic name for ota, tb_rule_engine.sq is a topic name for default SequentialByOriginator queue. # Check TB_QUEUE_CORE_OTA_TOPIC and TB_QUEUE_RE_SQ_TOPIC params consumer-properties-per-topic: tb_ota_package: + # Key-value properties for Kafka consumer per specific topic, e.g. tb_ota_package is a topic name for ota, tb_rule_engine.sq is a topic name for default SequentialByOriginator queue. Check TB_QUEUE_CORE_OTA_TOPIC and TB_QUEUE_RE_SQ_TOPIC params - key: max.poll.records + # Example of specific consumer properties value per topic value: "${TB_QUEUE_KAFKA_OTA_MAX_POLL_RECORDS:10}" tb_version_control: + # Example of specific consumer properties value per topic for VC - key: max.poll.interval.ms + # Example of specific consumer properties value per topic for VC value: "${TB_QUEUE_KAFKA_VC_MAX_POLL_INTERVAL_MS:600000}" # tb_rule_engine.sq: # - key: max.poll.records @@ -1129,102 +1350,182 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for JS Executor topics js-executor: "${TB_QUEUE_KAFKA_JE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:104857600;partitions:100;min.insync.replicas:1}" + # Kafka properties for OTA updates topic ota-updates: "${TB_QUEUE_KAFKA_OTA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Version Control topic version-control: "${TB_QUEUE_KAFKA_VC_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" consumer-stats: + # Prints lag between consumer group offset and last messages offset in Kafka topics enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" + # Statistics printing interval for Kafka's consumer-groups stats print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" + # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" aws_sqs: + # Use default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800 js-executor: "${TB_QUEUE_AWS_SQS_JE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds ota-updates: "${TB_QUEUE_AWS_SQS_OTA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds version-control: "${TB_QUEUE_AWS_SQS_VC_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue.Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consume again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consume again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consume again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consume again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # PubSub queue properties js-executor: "${TB_QUEUE_PUBSUB_JE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport Api subscribers, messages which will commit after ackDeadlineInSec period can be consume again version-control: "${TB_QUEUE_PUBSUB_VC_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus queue properties js-executor: "${TB_QUEUE_SERVICE_BUS_JE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Version Control queues version-control: "${TB_QUEUE_SERVICE_BUS_VC_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ queue properties js-executor: "${TB_QUEUE_RABBIT_MQ_JE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Version Control queues version-control: "${TB_QUEUE_RABBIT_MQ_VC_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}" ota: + # Default topic name for OTA updates topic: "${TB_QUEUE_CORE_OTA_TOPIC:tb_ota_package}" + # The interval of processing the OTA updates for devices. Used to avoid any harm to network due to many parallel OTA updates pack-interval-ms: "${TB_QUEUE_CORE_OTA_PACK_INTERVAL_MS:60000}" + # The size of OTA updates notifications fetched from the queue. The queue stores pairs of firmware and device ids pack-size: "${TB_QUEUE_CORE_OTA_PACK_SIZE:100}" + # Default topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}" vc: + # Default topic name for Kafka, RabbitMQ, etc. topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}" + # Number of partitions to associate with this queue. Used for scaling the number of messages that can be processed in parallel partitions: "${TB_QUEUE_VC_PARTITIONS:10}" + # Interval in milliseconds between polling of the messages if no new messages arrive poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" + # Timeout before retry all failed and timed-out messages from processing pack pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:180000}" + # Timeout for a request to VC-executor (for a request for the version of the entity, for a commit charge, etc.) request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:180000}" + # Queue settings for Kafka, RabbitMQ, etc. Limit for single message size msg-chunk-size: "${TB_QUEUE_VC_MSG_CHUNK_SIZE:250000}" js: # JS Eval request topic @@ -1242,19 +1543,24 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: + # Deprecated. Will be removed in nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:2000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" queues: - - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" - topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" - poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" - partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" - consumer-per-partition: "${TB_QUEUE_RE_MAIN_CONSUMER_PER_PARTITION:true}" - pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:2000}" + - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" # queue name + topic: "${TB_QUEUE_RE_MAIN_TOPIC:tb_rule_engine.main}" # queue topic + poll-interval: "${TB_QUEUE_RE_MAIN_POLL_INTERVAL_MS:25}" # poll interval + partitions: "${TB_QUEUE_RE_MAIN_PARTITIONS:10}" # number queue partitions + consumer-per-partition: "${TB_QUEUE_RE_MAIN_CONSUMER_PER_PARTITION:true}" # if true - use for each customer different partition + pack-processing-timeout: "${TB_QUEUE_RE_MAIN_PACK_PROCESSING_TIMEOUT_MS:2000}" # Timeout for processing a message pack submit-strategy: type: "${TB_QUEUE_RE_MAIN_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL # For BATCH only @@ -1266,12 +1572,12 @@ queue: 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. - - 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}" - partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" - consumer-per-partition: "${TB_QUEUE_RE_HP_CONSUMER_PER_PARTITION:true}" - pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:2000}" + - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" # queue name + topic: "${TB_QUEUE_RE_HP_TOPIC:tb_rule_engine.hp}" # queue topic + poll-interval: "${TB_QUEUE_RE_HP_POLL_INTERVAL_MS:25}" # poll interval + partitions: "${TB_QUEUE_RE_HP_PARTITIONS:10}" # number queue partitions + consumer-per-partition: "${TB_QUEUE_RE_HP_CONSUMER_PER_PARTITION:true}" # if true - use for each customer different partition + pack-processing-timeout: "${TB_QUEUE_RE_HP_PACK_PROCESSING_TIMEOUT_MS:2000}" # Timeout for processing a message pack submit-strategy: type: "${TB_QUEUE_RE_HP_SUBMIT_STRATEGY_TYPE:BURST}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL # For BATCH only @@ -1283,12 +1589,12 @@ queue: 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. - - 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}" - partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" - consumer-per-partition: "${TB_QUEUE_RE_SQ_CONSUMER_PER_PARTITION:true}" - pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:2000}" + - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" # queue name + topic: "${TB_QUEUE_RE_SQ_TOPIC:tb_rule_engine.sq}" # queue topic + poll-interval: "${TB_QUEUE_RE_SQ_POLL_INTERVAL_MS:25}" # poll interval + partitions: "${TB_QUEUE_RE_SQ_PARTITIONS:10}" # number queue partitions + consumer-per-partition: "${TB_QUEUE_RE_SQ_CONSUMER_PER_PARTITION:true}" # if true - use for each customer different partition + pack-processing-timeout: "${TB_QUEUE_RE_SQ_PACK_PROCESSING_TIMEOUT_MS:2000}" # Timeout for processing a message pack submit-strategy: type: "${TB_QUEUE_RE_SQ_SUBMIT_STRATEGY_TYPE:SEQUENTIAL_BY_ORIGINATOR}" # BURST, BATCH, SEQUENTIAL_BY_ORIGINATOR, SEQUENTIAL_BY_TENANT, SEQUENTIAL # For BATCH only @@ -1305,12 +1611,16 @@ queue: transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# Event configuration parameters event: debug: + # Maximum number of symbols per debug event. The event content will be truncated if needed max-symbols: "${TB_MAX_DEBUG_EVENT_SYMBOLS:4096}" +# General service parameters service: type: "${TB_SERVICE_TYPE:monolith}" # monolith or tb-core or tb-rule-engine # Unique id for this service (autogenerated if empty) @@ -1320,6 +1630,7 @@ service: # This Rule Engine will only be responsible for tenants with these profiles (in case 'isolation' option is enabled in profile). assigned_tenant_profiles: "${TB_RULE_ENGINE_ASSIGNED_TENANT_PROFILES:}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" @@ -1327,24 +1638,28 @@ metrics: # Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,). percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" +# Version control parameters vc: # Pool size for handling export tasks thread_pool_size: "${TB_VC_POOL_SIZE:2}" git: # Pool size for handling the git IO operations io_pool_size: "${TB_VC_GIT_POOL_SIZE:3}" + # Default storing repository path repositories-folder: "${TB_VC_GIT_REPOSITORIES_FOLDER:${java.io.tmpdir}/repositories}" +# Notification system parameters notification_system: + # Specify thread pool size for Notification System processing notification rules and notification sending. Recommend value < =10 thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:10}" rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' deduplication_durations: "${TB_NOTIFICATION_RULES_DEDUPLICATION_DURATIONS:NEW_PLATFORM_VERSION:0;RATE_LIMITS:14400000;}" +# General management parameters management: endpoints: web: exposure: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). - include: '${METRICS_ENDPOINTS_EXPOSE:info}' - + include: '${METRICS_ENDPOINTS_EXPOSE:info}' \ No newline at end of file diff --git a/pull_request_template.md b/pull_request_template.md index f65aa0a1f3..584ee6f4fc 100644 --- a/pull_request_template.md +++ b/pull_request_template.md @@ -26,6 +26,7 @@ Put your PR description here instead of this sentence. - [ ] If new dependency was added: the dependency tree is checked for conflicts. - [ ] If new service was added: the service is marked with corresponding @TbCoreComponent, @TbRuleEngineComponent, @TbTransportComponent, etc. - [ ] If new REST API was added: the RestClient.java was updated, issue for [Python REST client](https://github.com/thingsboard/thingsboard-python-rest-client) is created. +- [ ] If new yml property was added: make sure a description is added (above or near the property). diff --git a/tools/src/main/python/check_yml_file.py b/tools/src/main/python/check_yml_file.py new file mode 100644 index 0000000000..2c65876f70 --- /dev/null +++ b/tools/src/main/python/check_yml_file.py @@ -0,0 +1,105 @@ +import sys +import re + +def extract_properties_with_comments(yaml_file_path): + properties = {} + + with open(yaml_file_path, 'r') as file: + lines = file.readlines() + index = 0 + key_level_map = {0 : ''} + parse_line('', '', key_level_map, 0, index, lines, properties) + + return properties + + +def parse_line(table_name, comment, key_level_map, parent_line_level, index, lines, properties): + if index >= len(lines): + return + line = lines[index] + line_level = (len(line) - len(line.lstrip())) if line.strip() else 0 + if line_level == 0: + key_level_map = {0 : ''} + line = line.strip() + # if line is empty - parse next line + if not line: + index = index + 1 + parse_line(table_name, comment, key_level_map, line_level, index, lines, properties) + # if line is a comment - save comment and parse next line + elif line.startswith('#'): + if line_level == 0: + table_name = line.lstrip('#') + elif line_level == parent_line_level: + comment = comment + '\n' + line.lstrip('#') + else: + comment = line.lstrip('#') + index = index + 1 + parse_line(table_name, comment, key_level_map, line_level, index, lines, properties) + else: + # Check if it's a property line + if ':' in line: + # clean comment if level was changed + if line_level != parent_line_level: + comment = '' + key, value = line.split(':', 1) + if key.startswith('- '): + key = key.lstrip('- ') + key_level_map[line_level] = key + value = value.strip() + if value.split('#')[0]: + current_key = '' + for k in key_level_map.keys(): + if k <= line_level: + current_key = ((current_key + '.') if current_key else '') + key_level_map[k] + properties[current_key] = (value, comment, table_name) + comment = '' + index = index + 1 + parse_line(table_name, comment, key_level_map, line_level, index, lines, properties) + +def extract_property_info(properties): + rows = [] + for property_name, value in properties.items(): + if '#' in value[0]: + value_parts = value[0].split('#') + comment = value_parts[1] + else: + comment = value[1] + pattern = r'\"\$\{(.*?)\:(.*?)\}\"' + match = re.match(pattern, value[0]) + if match is not None: + rows.append((property_name, match.group(1), match.group(2), comment, value[2])) + else: + rows.append((property_name, "", value[0].split('#')[0], comment, value[2])) + return rows + +def check_descriptions(properties): + variables_without_description = [] + for row in properties: + # Extract information from the tuple + property_name, env_variable, default_value, comment, table_name = row + if comment == '' or len(comment) < 5 : + variables_without_description.append(property_name) + + return variables_without_description + + +if __name__ == '__main__': + sys. setrecursionlimit(10000) + # path to the YAML file + input_yaml_file = "application/src/main/resources/thingsboard.yml" + + # Parse yml file to map where key is property key path with '.' separator + # and value is an object (env_name_with_default_value, comment, table_name) + properties = extract_properties_with_comments(input_yaml_file) + + # Extract property information (extract env name, default value and comment nearby property) + property_info = extract_property_info(properties) + + # Check all properies have descriptions + variables_without_desc = check_descriptions(property_info) + + if len(variables_without_desc) > 0: + print(f"There are some yml properties without valid description: (total {len(variables_without_desc)}) {variables_without_desc}.") + exit(1) + else: + print("All yml properties have valid description.") \ No newline at end of file From a7daf55a38d291f35e857ec6728865e97c94dcc4 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 5 Oct 2023 14:43:42 +0300 Subject: [PATCH 132/267] fixed github action yml file --- ...{check_yml_parameter_descriptions.yml => check_yml_file.yml} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename .github/workflows/{check_yml_parameter_descriptions.yml => check_yml_file.yml} (88%) diff --git a/.github/workflows/check_yml_parameter_descriptions.yml b/.github/workflows/check_yml_file.yml similarity index 88% rename from .github/workflows/check_yml_parameter_descriptions.yml rename to .github/workflows/check_yml_file.yml index 240222d1b1..3ec0a64439 100644 --- a/.github/workflows/check_yml_parameter_descriptions.yml +++ b/.github/workflows/check_yml_file.yml @@ -21,4 +21,4 @@ jobs: AGENT_TOOLSDIRECTORY: /opt/hostedtoolcache - name: Run Verification Script - run: python3 tools/src/main/python/check_env_variables.py + run: python3 tools/src/main/python/check_yml_file.py From 12f140c5e28046e4cdc03cde7ab2fa203276ef83 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 5 Oct 2023 14:49:48 +0300 Subject: [PATCH 133/267] renamed github action yml file --- .github/workflows/{check_yml_file.yml => main.yml} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/workflows/{check_yml_file.yml => main.yml} (89%) diff --git a/.github/workflows/check_yml_file.yml b/.github/workflows/main.yml similarity index 89% rename from .github/workflows/check_yml_file.yml rename to .github/workflows/main.yml index 3ec0a64439..f420254f34 100644 --- a/.github/workflows/check_yml_file.yml +++ b/.github/workflows/main.yml @@ -1,11 +1,11 @@ -name: Check yml parameters have description +name: check_yml on: pull_request: paths: - 'application/src/main/resources/thingsboard.yml' jobs: build: - name: check + name: Check yml parameters have description runs-on: ubuntu-20.04 steps: From 5d494f81dd171a4022a78058271afc88cc4c8fab Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 5 Oct 2023 15:25:05 +0300 Subject: [PATCH 134/267] renamed github action job name --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f420254f34..5a4d79428c 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -1,11 +1,11 @@ -name: check_yml +name: check_yml_file on: pull_request: paths: - 'application/src/main/resources/thingsboard.yml' jobs: build: - name: Check yml parameters have description + name: check_yml_file runs-on: ubuntu-20.04 steps: From 4c00b839e687d2119a84cc7e6f5167e8c2de9bbc Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 5 Oct 2023 17:33:06 +0300 Subject: [PATCH 135/267] add yml parameter description --- application/src/main/resources/thingsboard.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index a94ecc8de0..b73c4f1fda 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1554,6 +1554,7 @@ queue: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" + # Max length of error message that is printed by statistics max-error-message-length: "${TB_QUEUE_RULE_ENGINE_MAX_ERROR_MESSAGE_LENGTH:4096}" queues: - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" # queue name From 2492b81d3403d5de852c2eba7e0c93522db9ce78 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 5 Oct 2023 17:52:49 +0300 Subject: [PATCH 136/267] UI: Wind speed and direction widget. --- .../widget_bundles/weather_widgets.json | 13 + .../wind_speed_and_direction.json | 29 ++ .../DefaultSystemDataLoaderService.java | 1 + .../sql/widget/WidgetTypeInfoRepository.java | 2 +- ui-ngx/package.json | 1 + ui-ngx/src/app/core/utils.ts | 4 +- .../basic/basic-widget-config.module.ts | 12 +- .../basic/common/data-key-row.component.html | 37 +- .../basic/common/data-key-row.component.scss | 25 ++ .../basic/common/data-key-row.component.ts | 138 +++++--- .../common/data-keys-panel.component.html | 9 + .../basic/common/data-keys-panel.component.ts | 17 - ...peed-direction-basic-config.component.html | 213 +++++++++++ ...-speed-direction-basic-config.component.ts | 291 +++++++++++++++ .../battery-level-widget.component.html | 4 +- .../battery-level-widget.component.scss | 214 ++++++----- .../battery-level-widget.component.ts | 6 +- ...d-direction-widget-settings.component.html | 102 ++++++ ...eed-direction-widget-settings.component.ts | 139 ++++++++ .../lib/settings/widget-settings.module.ts | 12 +- ...wind-speed-direction-widget.component.html | 25 ++ ...wind-speed-direction-widget.component.scss | 49 +++ .../wind-speed-direction-widget.component.ts | 333 ++++++++++++++++++ .../wind-speed-direction-widget.models.ts | 108 ++++++ .../widget/widget-components.module.ts | 9 +- .../shared/models/widget-settings.models.ts | 41 +++ .../assets/locale/locale.constant-en_US.json | 21 ++ .../wind-speed-direction/advanced-layout.svg | 187 ++++++++++ .../wind-speed-direction/default-layout.svg | 167 +++++++++ .../simplified-layout.svg | 153 ++++++++ ui-ngx/src/form.scss | 12 +- ui-ngx/yarn.lock | 5 + 32 files changed, 2167 insertions(+), 212 deletions(-) create mode 100644 application/src/main/data/json/system/widget_bundles/weather_widgets.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_and_direction.json create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts create mode 100644 ui-ngx/src/assets/widget/wind-speed-direction/advanced-layout.svg create mode 100644 ui-ngx/src/assets/widget/wind-speed-direction/default-layout.svg create mode 100644 ui-ngx/src/assets/widget/wind-speed-direction/simplified-layout.svg diff --git a/application/src/main/data/json/system/widget_bundles/weather_widgets.json b/application/src/main/data/json/system/widget_bundles/weather_widgets.json new file mode 100644 index 0000000000..a38c139cf0 --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/weather_widgets.json @@ -0,0 +1,13 @@ +{ + "widgetsBundle": { + "alias": "weather_widgets", + "title": "Weather widgets", + "image": null, + "description": null, + "externalId": null, + "name": "Weather widgets" + }, + "widgetTypeFqns": [ + "wind_speed_and_direction" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json new file mode 100644 index 0000000000..1c4f7ecb7c --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json @@ -0,0 +1,29 @@ +{ + "fqn": "wind_speed_and_direction", + "name": "Wind speed and direction", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays the latest values of the wind speed and direction.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-wind-speed-direction-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-wind-speed-direction-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 30) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind speed and direction\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"air\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "wind", + "weather", + "compass", + "degrees" + ] +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 29dcd601a1..a40913a281 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -532,6 +532,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("html_widgets"); this.deleteSystemWidgetBundle("tables"); this.deleteSystemWidgetBundle("count_widgets"); + this.deleteSystemWidgetBundle("weather_widgets"); installScripts.loadSystemWidgets(); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java index 27f4ef918f..f3f3bf5139 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetTypeInfoRepository.java @@ -37,7 +37,7 @@ public interface WidgetTypeInfoRepository extends JpaRepository { - if (dataKey.label === label) { + if (dataKey?.label === label) { i++; label = name + ' ' + i; matches = true; @@ -777,7 +777,7 @@ export function genNextLabel(name: string, datasources: Datasource[]): string { } if (datasource.latestDataKeys) { datasource.latestDataKeys.forEach((dataKey) => { - if (dataKey.label === label) { + if (dataKey?.label === label) { i++; label = name + ' ' + i; matches = true; diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 41115904b3..3cc2eddb7d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -58,6 +58,9 @@ import { import { BatteryLevelBasicConfigComponent } from '@home/components/widget/config/basic/indicator/battery-level-basic-config.component'; +import { + WindSpeedDirectionBasicConfigComponent +} from '@home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component'; @NgModule({ declarations: [ @@ -75,7 +78,8 @@ import { DataKeysPanelComponent, AlarmCountBasicConfigComponent, EntityCountBasicConfigComponent, - BatteryLevelBasicConfigComponent + BatteryLevelBasicConfigComponent, + WindSpeedDirectionBasicConfigComponent ], imports: [ CommonModule, @@ -97,7 +101,8 @@ import { DataKeysPanelComponent, AlarmCountBasicConfigComponent, EntityCountBasicConfigComponent, - BatteryLevelBasicConfigComponent + BatteryLevelBasicConfigComponent, + WindSpeedDirectionBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -113,5 +118,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type -
+
{{ 'datakey.timeseries' | translate }} @@ -23,8 +23,8 @@ - - +
@@ -67,8 +67,8 @@ #keyInput [formControl]="keyFormControl" matAutocompleteOrigin - [fxHide]="!!modelValue.type" - [readonly]="!!modelValue.type" + [fxHide]="!!modelValue?.type" + [readonly]="!!modelValue?.type" #origin="matAutocompleteOrigin" [matAutocompleteConnectedTo]="origin" (focusin)="onKeyInputFocus()" @@ -139,7 +139,7 @@ - +
@@ -147,25 +147,28 @@ formControlName="color">
-
+
-
+
+
widget-config.decimals-suffix
-
- +
+
+ +
+ + +
+ +
+
+
+
@@ -63,7 +63,7 @@ : ''" formControlName="icon"> - +
@@ -76,7 +76,7 @@
- +
@@ -86,7 +86,7 @@ - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts index 5a2a91b56b..4018549863 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/widget-settings-common.module.ts @@ -27,7 +27,10 @@ import { } from '@home/components/widget/lib/settings/common/image-cards-select.component'; import { FontSettingsComponent } from '@home/components/widget/lib/settings/common/font-settings.component'; import { FontSettingsPanelComponent } from '@home/components/widget/lib/settings/common/font-settings-panel.component'; -import { ColorSettingsComponent } from '@home/components/widget/lib/settings/common/color-settings.component'; +import { + ColorSettingsComponent, + ColorSettingsComponentService +} from '@home/components/widget/lib/settings/common/color-settings.component'; import { ColorSettingsPanelComponent } from '@home/components/widget/lib/settings/common/color-settings-panel.component'; @@ -83,6 +86,9 @@ import { LegendConfigComponent, WidgetFontComponent, CountWidgetSettingsComponent + ], + providers: [ + ColorSettingsComponentService ] }) export class WidgetSettingsCommonModule { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html index 1221e5bfc2..7e53d17df1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html @@ -40,18 +40,18 @@ [autoScale]="batteryLevelWidgetSettingsForm.get('autoScaleValueSize').value" [previewText]="valuePreviewFn"> - +
{{ 'widgets.battery-level.battery-level-color' | translate }}
- +
{{ 'widgets.battery-level.battery-shape-color' | translate }}
- +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html index e81519ff3c..1bf2095b10 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.html @@ -36,7 +36,7 @@ [initialPreviewStyle]="{ color: windSpeedDirectionWidgetSettingsForm.get('centerValueColor').value?.color }" [previewText]="centerValuePreviewFn"> - +
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 40abb989c1..e755f16420 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5201,7 +5201,8 @@ "value-range": "Value range", "from": "From", "to": "To", - "color-function": "Color function" + "color-function": "Color function", + "copy-color-settings-from": "Copy color settings from" }, "dashboard-state": { "dashboard-state-settings": "Dashboard state settings", From bc096de3f702290e7ad926b7916db9a34e911e06 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 10 Oct 2023 09:47:55 +0300 Subject: [PATCH 150/267] UI: Hide edit button if profile is not selected --- .../profile/tenant-profile-autocomplete.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html index 2c5a019b70..a27bff5165 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-autocomplete.component.html @@ -35,7 +35,7 @@ (click)="clear()"> close - + Date: Tue, 10 Oct 2023 13:41:45 +0300 Subject: [PATCH 152/267] UI: Implement sections count parameter for battery level widget. --- .../battery-level-basic-config.component.html | 6 +++++ .../battery-level-basic-config.component.ts | 20 +++++++++++--- .../battery-level-widget.component.html | 3 ++- .../battery-level-widget.component.ts | 26 ++++++++++++++++++- .../indicator/battery-level-widget.models.ts | 2 ++ ...ttery-level-widget-settings.component.html | 6 +++++ ...battery-level-widget-settings.component.ts | 21 ++++++++++++--- .../assets/locale/locale.constant-en_US.json | 3 ++- 8 files changed, 78 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.html b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.html index 245ae063a1..1d67d587fe 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.html @@ -40,6 +40,12 @@ {{ batteryLevelLayoutTranslationMap.get(layout) | translate }} +
+
{{ 'widgets.battery-level.sections-count' | translate }}
+ + + +
{{ 'widget-config.title' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts index 482a8dd2c3..bb6af9d5ad 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Injector } from '@angular/core'; +import { Component } from '@angular/core'; import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; @@ -35,6 +35,7 @@ import { formatValue, isUndefined } from '@core/utils'; import { cssSizeToStrSize, resolveCssSize } from '@shared/models/widget-settings.models'; import { batteryLevelDefaultSettings, + BatteryLevelLayout, batteryLevelLayoutImages, batteryLevelLayouts, batteryLevelLayoutTranslations, @@ -67,9 +68,13 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent valuePreviewFn = this._valuePreviewFn.bind(this); + get sectionsCountEnabled(): boolean { + const layout: BatteryLevelLayout = this.batteryLevelWidgetConfigForm.get('layout').value; + return [BatteryLevelLayout.vertical_divided, BatteryLevelLayout.horizontal_divided].includes(layout); + } + constructor(protected store: Store, protected widgetConfigComponent: WidgetConfigComponent, - private $injector: Injector, private fb: UntypedFormBuilder) { super(store, widgetConfigComponent); } @@ -90,6 +95,7 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent datasources: [configData.config.datasources, []], layout: [settings.layout, []], + sectionsCount: [settings.sectionsCount, [Validators.min(2), Validators.max(20)]], showTitle: [configData.config.showTitle, []], title: [configData.config.title, []], @@ -136,6 +142,7 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; this.widgetConfig.config.settings.layout = config.layout; + this.widgetConfig.config.settings.sectionsCount = config.sectionsCount; this.widgetConfig.config.settings.showValue = config.showValue; this.widgetConfig.config.settings.autoScaleValueSize = config.autoScaleValueSize === true; @@ -155,13 +162,15 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent } protected validatorTriggers(): string[] { - return ['showTitle', 'showIcon', 'showValue']; + return ['showTitle', 'showIcon', 'showValue', 'layout']; } protected updateValidators(emitEvent: boolean, trigger?: string) { const showTitle: boolean = this.batteryLevelWidgetConfigForm.get('showTitle').value; const showIcon: boolean = this.batteryLevelWidgetConfigForm.get('showIcon').value; const showValue: boolean = this.batteryLevelWidgetConfigForm.get('showValue').value; + const layout: BatteryLevelLayout = this.batteryLevelWidgetConfigForm.get('layout').value; + const divided = [BatteryLevelLayout.vertical_divided, BatteryLevelLayout.horizontal_divided].includes(layout); if (showTitle) { this.batteryLevelWidgetConfigForm.get('title').enable(); @@ -199,6 +208,11 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent this.batteryLevelWidgetConfigForm.get('valueFont').disable(); this.batteryLevelWidgetConfigForm.get('valueColor').disable(); } + if (divided) { + this.batteryLevelWidgetConfigForm.get('sectionsCount').enable(); + } else { + this.batteryLevelWidgetConfigForm.get('sectionsCount').disable(); + } } private getCardButtons(config: WidgetConfig): string[] { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.html index d5739683b7..cc2fe2cf8f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.html @@ -22,7 +22,7 @@
-
+
@@ -38,5 +38,6 @@
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts index 6e9f8323be..9161764223 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts @@ -117,7 +117,9 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView value: number; - batterySections: boolean[] = [false, false, false, false]; + batterySections: boolean[]; + dividedBorderRadius: string; + dividedGap: string; batteryLevelColor: ColorProcessor; @@ -158,6 +160,26 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView this.vertical = [BatteryLevelLayout.vertical_solid, BatteryLevelLayout.vertical_divided].includes(this.layout); this.layoutClass = this.vertical ? 'vertical' : 'horizontal'; this.solid = [BatteryLevelLayout.vertical_solid, BatteryLevelLayout.horizontal_solid].includes(this.layout); + if (!this.solid) { + let sectionsCount = this.settings.sectionsCount; + if (!sectionsCount) { + sectionsCount = 4; + } + sectionsCount = Math.min(Math.max(sectionsCount, 2), 20); + this.batterySections = Array.from(Array(sectionsCount), () => false); + const gap = 1 + (24 - sectionsCount) / 10; + this.dividedGap = `${gap}%`; + const containerAspect = 0.5567; + const sectionHeight = (100 - (gap * (sectionsCount - 1))) / sectionsCount; + const sectionAspect = 100 * containerAspect / sectionHeight; + const rad1 = 8.425 - sectionsCount * 0.32125; + const rad2 = rad1 * sectionAspect; + if (this.vertical) { + this.dividedBorderRadius = `${rad1}% / ${rad2}%`; + } else { + this.dividedBorderRadius = `${rad2}% / ${rad1}%`; + } + } this.showValue = this.settings.showValue; this.autoScaleValueSize = this.showValue && this.settings.autoScaleValueSize; @@ -243,6 +265,8 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView const valueLineHeight = ratios.valueLineHeightRaio * boxSize; this.setValueFontSize(valueFontSize, valueLineHeight, boxWidth); } + const fontSize = parseInt(window.getComputedStyle(this.batteryLevelValue.nativeElement).fontSize, 10) || 10; + this.renderer.setStyle(this.batteryLevelValue.nativeElement, 'minWidth', `${Math.min(fontSize*4, boxWidth)}px`); } let height = this.batteryLevelContent.nativeElement.getBoundingClientRect().height; const width = height * verticalBatteryDimensions.shapeAspectRatio; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts index 8d8724f901..34c00a4b92 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.models.ts @@ -53,6 +53,7 @@ export const batteryLevelLayoutImages = new Map( export interface BatteryLevelWidgetSettings { layout: BatteryLevelLayout; + sectionsCount: number; showValue: boolean; autoScaleValueSize: boolean; valueFont: Font; @@ -64,6 +65,7 @@ export interface BatteryLevelWidgetSettings { export const batteryLevelDefaultSettings: BatteryLevelWidgetSettings = { layout: BatteryLevelLayout.vertical_solid, + sectionsCount: 4, showValue: true, autoScaleValueSize: true, valueFont: { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html index 7e53d17df1..2b841ca9f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.html @@ -28,6 +28,12 @@ {{ batteryLevelLayoutTranslationMap.get(layout) | translate }} +
+
{{ 'widgets.battery-level.sections-count' | translate }}
+ + + +
{{ 'widgets.battery-level.value' | translate }} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.ts index 627bf00cd2..6c6fecf662 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/battery-level-widget-settings.component.ts @@ -16,12 +16,12 @@ import { Component, Injector } from '@angular/core'; import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; -import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { formatValue } from '@core/utils'; import { - batteryLevelDefaultSettings, + batteryLevelDefaultSettings, BatteryLevelLayout, batteryLevelLayoutImages, batteryLevelLayouts, batteryLevelLayoutTranslations @@ -43,6 +43,11 @@ export class BatteryLevelWidgetSettingsComponent extends WidgetSettingsComponent valuePreviewFn = this._valuePreviewFn.bind(this); + get sectionsCountEnabled(): boolean { + const layout: BatteryLevelLayout = this.batteryLevelWidgetSettingsForm.get('layout').value; + return [BatteryLevelLayout.vertical_divided, BatteryLevelLayout.horizontal_divided].includes(layout); + } + constructor(protected store: Store, private $injector: Injector, private fb: UntypedFormBuilder) { @@ -60,6 +65,7 @@ export class BatteryLevelWidgetSettingsComponent extends WidgetSettingsComponent protected onSettingsSet(settings: WidgetSettings) { this.batteryLevelWidgetSettingsForm = this.fb.group({ layout: [settings.layout, []], + sectionsCount: [settings.sectionsCount, [Validators.min(2), Validators.max(20)]], showValue: [settings.showValue, []], autoScaleValueSize: [settings.autoScaleValueSize, []], @@ -74,11 +80,13 @@ export class BatteryLevelWidgetSettingsComponent extends WidgetSettingsComponent } protected validatorTriggers(): string[] { - return ['showValue']; + return ['showValue', 'layout']; } protected updateValidators(emitEvent: boolean) { const showValue: boolean = this.batteryLevelWidgetSettingsForm.get('showValue').value; + const layout: BatteryLevelLayout = this.batteryLevelWidgetSettingsForm.get('layout').value; + const divided = [BatteryLevelLayout.vertical_divided, BatteryLevelLayout.horizontal_divided].includes(layout); if (showValue) { this.batteryLevelWidgetSettingsForm.get('autoScaleValueSize').enable(); @@ -90,9 +98,16 @@ export class BatteryLevelWidgetSettingsComponent extends WidgetSettingsComponent this.batteryLevelWidgetSettingsForm.get('valueColor').disable(); } + if (divided) { + this.batteryLevelWidgetSettingsForm.get('sectionsCount').enable(); + } else { + this.batteryLevelWidgetSettingsForm.get('sectionsCount').disable(); + } + this.batteryLevelWidgetSettingsForm.get('autoScaleValueSize').updateValueAndValidity({emitEvent}); this.batteryLevelWidgetSettingsForm.get('valueFont').updateValueAndValidity({emitEvent}); this.batteryLevelWidgetSettingsForm.get('valueColor').updateValueAndValidity({emitEvent}); + this.batteryLevelWidgetSettingsForm.get('sectionsCount').updateValueAndValidity({emitEvent}); } private _valuePreviewFn(): 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 e755f16420..0fdf48d12c 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5057,7 +5057,8 @@ "auto-scale": "Auto scale", "battery-level-color": "Battery level color", "battery-shape-color": "Battery shape color", - "battery-level-card-style": "Battery level card style" + "battery-level-card-style": "Battery level card style", + "sections-count": "Sections count" }, "chart": { "common-settings": "Common settings", From fd2bf34508db29a7f308c26e0b2fc12dc137f937 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 10 Oct 2023 15:44:58 +0300 Subject: [PATCH 153/267] UI: Fixed tenant profile dialog --- .../tenant-profile-dialog.component.html | 2 +- .../tenant-profile-dialog.component.scss | 23 +++++++++++++++++++ .../tenant-profile-dialog.component.ts | 2 +- .../queue/queue-form.component.html | 12 ++++++---- 4 files changed, 33 insertions(+), 6 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.scss diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.html b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.html index af4aec4e80..c9d807d39e 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.html @@ -15,7 +15,7 @@ limitations under the License. --> -
+

{{ (isAdd ? 'tenant-profile.add' : 'tenant-profile.edit' ) | translate }}

diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.scss b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.scss new file mode 100644 index 0000000000..a881fa5023 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.scss @@ -0,0 +1,23 @@ +/** + * Copyright © 2016-2023 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 ::ng-deep { + tb-tenant-profile { + .mat-padding { + padding: 0; + + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts index 96ead6405d..b5f910821a 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile-dialog.component.ts @@ -43,7 +43,7 @@ export interface TenantProfileDialogData { selector: 'tb-tenant-profile-dialog', templateUrl: './tenant-profile-dialog.component.html', providers: [{provide: ErrorStateMatcher, useExisting: TenantProfileDialogComponent}], - styleUrls: [] + styleUrls: ['tenant-profile-dialog.component.scss'] }) export class TenantProfileDialogComponent extends DialogComponent implements ErrorStateMatcher, AfterViewInit { diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html index 960e81f8b4..53262717f9 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.html @@ -91,9 +91,10 @@
- + queue.retries + {{ 'queue.retries-required' | translate }} @@ -102,9 +103,10 @@ {{ 'queue.retries-min-value' | translate }} - + queue.failure-percentage + {{ 'queue.failure-percentage-required' | translate }} @@ -119,9 +121,10 @@ {{ 'queue.failure-percentage-max-value' | translate }} - + queue.pause-between-retries + {{ 'queue.pause-between-retries-required' | translate }} @@ -130,9 +133,10 @@ {{ 'queue.pause-between-retries-min-value' | translate }} - + queue.max-pause-between-retries + {{ 'queue.max-pause-between-retries-required' | translate }} From 3ab6b0e2b7a9216a52b5344954d015af2084080d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 10 Oct 2023 17:23:12 +0300 Subject: [PATCH 154/267] UI: Fix data keys chips validation. --- .../widget/config/data-keys.component.ts | 70 ++++++++++++++----- .../widget/widget-config.component.ts | 1 + 2 files changed, 55 insertions(+), 16 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts index 02060db364..24b2f6345b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.ts @@ -33,13 +33,13 @@ import { import { AbstractControl, ControlValueAccessor, - FormGroupDirective, + FormGroupDirective, NG_VALIDATORS, NG_VALUE_ACCESSOR, NgForm, UntypedFormBuilder, UntypedFormControl, UntypedFormGroup, - ValidationErrors + ValidationErrors, Validator } from '@angular/forms'; import { Observable, of } from 'rxjs'; import { filter, map, mergeMap, publishReplay, refCount, share, tap } from 'rxjs/operators'; @@ -62,7 +62,7 @@ import { DataKeyConfigDialogComponent, DataKeyConfigDialogData } from '@home/components/widget/config/data-key-config-dialog.component'; -import { deepClone, guid, isDefinedAndNotNull, isUndefined } from '@core/utils'; +import { deepClone, guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils'; import { Dashboard } from '@shared/models/dashboard.models'; import { AggregationType } from '@shared/models/time/time.models'; import { DndDropEvent } from 'ngx-drag-drop/lib/dnd-dropzone.directive'; @@ -81,15 +81,20 @@ import { TbPopoverService } from '@shared/components/popover.service'; provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => DataKeysComponent), multi: true - } /*, + }, + { + provide: NG_VALIDATORS, + useExisting: forwardRef(() => DataKeysComponent), + multi: true, + }, { provide: ErrorStateMatcher, useExisting: DataKeysComponent - } */ + } ], encapsulation: ViewEncapsulation.None }) -export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChanges, ErrorStateMatcher { +export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChanges, ErrorStateMatcher, Validator { public get hideDataKeyLabel(): boolean { return this.datasourceComponent.hideDataKeyLabel; @@ -205,6 +210,9 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange private propagateChange = (v: any) => { }; + private keysRequired = this._keysRequired.bind(this); + private keysValidator = this._keysValidator.bind(this); + constructor(private store: Store, @SkipSelf() private errorStateMatcher: ErrorStateMatcher, private datasourceComponent: DatasourceComponent, @@ -220,12 +228,16 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange } updateValidators() { - this.keysListFormGroup.get('keys').setValidators(this.required ? [this.keysRequired] : []); + if (this.required) { + this.keysListFormGroup.get('keys').addValidators(this.keysRequired); + } else { + this.keysListFormGroup.get('keys').removeValidators(this.keysRequired); + } this.keysListFormGroup.get('keys').updateValueAndValidity(); } - keysRequired(control: AbstractControl): ValidationErrors | null { - const value = control.value; + private _keysRequired(control: AbstractControl): ValidationErrors | null { + const value = this.modelValue; if (value && Array.isArray(value) && value.length) { return null; } else { @@ -233,8 +245,23 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange } } + private _keysValidator(control: AbstractControl): ValidationErrors | null { + const value = this.modelValue; + if (value && Array.isArray(value)) { + if (value.some(v => isObject(v) && (!v.type || !v.name))) { + return { + dataKey: true + }; + } + } + return null; + } + registerOnChange(fn: any): void { this.propagateChange = fn; + if (!this.keysListFormGroup.valid) { + this.propagateChange(this.modelValue); + } } registerOnTouched(fn: any): void { @@ -242,9 +269,12 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange ngOnInit() { this.keysListFormGroup = this.fb.group({ - keys: [null, this.required ? [this.keysRequired] : []], + keys: [null, [this.keysValidator]], key: [null] }); + if (this.required) { + this.keysListFormGroup.get('keys').addValidators(this.keysRequired); + } this.alarmKeys = []; for (const name of Object.keys(alarmFields)) { this.alarmKeys.push({ @@ -335,8 +365,8 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange } else { this.keys = []; } - this.keysListFormGroup.get('keys').setValue(this.keys); this.modelValue = this.keys.length ? [...this.keys] : null; + this.keysListFormGroup.get('keys').setValue(this.keys); if (this.keyInput) { this.keyInput.nativeElement.value = ''; } @@ -374,7 +404,7 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange isErrorState(control: UntypedFormControl | null, form: FormGroupDirective | NgForm | null): boolean { const originalErrorState = this.errorStateMatcher.isErrorState(control, form); - const customErrorState = this.required && (!this.modelValue || !this.modelValue.length); + const customErrorState = this.keysListFormGroup.get('keys').hasError('dataKey'); return originalErrorState || customErrorState; } @@ -395,12 +425,20 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange this.keysListFormGroup.get('keys').setValue(this.keys); } else { this.keys = []; - this.keysListFormGroup.get('keys').setValue(this.keys); this.modelValue = null; + this.keysListFormGroup.get('keys').setValue(this.keys); } this.dirty = true; } + validate(c: UntypedFormControl) { + return (this.keysListFormGroup.get('keys').hasError('dataKey')) ? { + dataKeys: { + valid: false, + }, + } : null; + } + onFocus() { if (this.dirty) { this.keysListFormGroup.get('key').updateValueAndValidity({onlySelf: true, emitEvent: true}); @@ -441,8 +479,8 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange const index = this.keys.indexOf(key); if (index >= 0) { this.keys.splice(index, 1); - this.keysListFormGroup.get('keys').setValue(this.keys); this.modelValue.splice(index, 1); + this.keysListFormGroup.get('keys').setValue(this.keys); if (!this.modelValue.length) { this.modelValue = null; } @@ -468,8 +506,8 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange index = this.keys.length; } moveItemInArray(this.keys, this.dragIndex, index); - this.keysListFormGroup.get('keys').setValue(this.keys); moveItemInArray(this.modelValue, this.dragIndex, index); + this.keysListFormGroup.get('keys').setValue(this.keys); this.dragIndex = -1; this.propagateChange(this.modelValue); } @@ -525,8 +563,8 @@ export class DataKeysComponent implements ControlValueAccessor, OnInit, OnChange }).afterClosed().subscribe((updatedDataKey) => { if (updatedDataKey) { this.keys[index] = updatedDataKey; - this.keysListFormGroup.get('keys').setValue(this.keys); this.modelValue[index] = updatedDataKey; + this.keysListFormGroup.get('keys').setValue(this.keys); this.propagateChange(this.modelValue); } }); 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 b4495a2b95..0f569c5ce9 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 @@ -435,6 +435,7 @@ export class WidgetConfigComponent extends PageComponent implements OnInit, OnDe this.basicModeComponentChangeSubscription = this.basicModeComponent.widgetConfigChanged.subscribe((data) => { this.modelValue = data; this.propagateChange(this.modelValue); + this.cd.markForCheck(); }); this.cd.markForCheck(); }, 0); From 8edab0a5cdeb725bd51d148e35b46315e5654b90 Mon Sep 17 00:00:00 2001 From: rusikv Date: Tue, 10 Oct 2023 17:31:30 +0300 Subject: [PATCH 155/267] UI: enabled all delete strategies for multiple deleterion of timeseries --- .../attribute/attribute-table.component.ts | 36 +++++++++---------- .../delete-timeseries-panel.component.ts | 17 ++------- 2 files changed, 19 insertions(+), 34 deletions(-) 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 872e124f3a..119c7a829f 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 @@ -39,7 +39,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 { merge, Subject } from 'rxjs'; +import { forkJoin, merge, Observable, Subject } from 'rxjs'; import { debounceTime, distinctUntilChanged, takeUntil } from 'rxjs/operators'; import { EntityId } from '@shared/models/id/entity-id'; import { @@ -84,15 +84,11 @@ import { AddWidgetToDashboardDialogComponent, AddWidgetToDashboardDialogData } from '@home/components/attribute/add-widget-to-dashboard-dialog.component'; -import { deepClone, isUndefinedOrNull } from '@core/utils'; +import { deepClone } from '@core/utils'; import { Filters } from '@shared/models/query/query.models'; import { hidePageSizePixelValue } from '@shared/models/constants'; import { ResizeObserver } from '@juggle/resize-observer'; -import { - DELETE_TIMESERIES_PANEL_DATA, - DeleteTimeseriesPanelComponent, - DeleteTimeseriesPanelData -} from '@home/components/attribute/delete-timeseries-panel.component'; +import { DeleteTimeseriesPanelComponent } from '@home/components/attribute/delete-timeseries-panel.component'; import { FormBuilder } from '@angular/forms'; @@ -392,7 +388,6 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI if ($event) { $event.stopPropagation(); } - const isMultipleDeletion = isUndefinedOrNull(telemetry) && this.dataSource.selection.selected.length > 1; const target = $event.target || $event.srcElement || $event.currentTarget; const config = new OverlayConfig({ panelClass: 'tb-filter-panel', @@ -415,12 +410,6 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI }); const providers: StaticProvider[] = [ - { - provide: DELETE_TIMESERIES_PANEL_DATA, - useValue: { - isMultipleDeletion - } as DeleteTimeseriesPanelData - }, { provide: OverlayRef, useValue: overlayRef @@ -433,6 +422,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI if (componentRef.instance.result !== null) { const result = componentRef.instance.result; const deleteTimeseries = telemetry ? [telemetry]: this.dataSource.selection.selected; + const tasks: Observable[] = []; let deleteAllDataForKeys = false; let rewriteLatestIfDeleted = false; let startTs = null; @@ -448,8 +438,12 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI break; case TimeseriesDeleteStrategy.DELETE_LATEST_VALUE: rewriteLatestIfDeleted = result.rewriteLatest; - startTs = deleteTimeseries[0].lastUpdateTs; - endTs = startTs + 1; + for (const ts of deleteTimeseries) { + startTs = ts.lastUpdateTs; + endTs = startTs + 1; + tasks.push(this.attributeService.deleteEntityTimeseries(this.entityIdValue, [ts], + deleteAllDataForKeys, startTs, endTs, rewriteLatestIfDeleted, deleteLatest)); + } break; case TimeseriesDeleteStrategy.DELETE_ALL_DATA_FOR_TIME_PERIOD: startTs = result.startDateTime.getTime(); @@ -457,9 +451,13 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI rewriteLatestIfDeleted = result.rewriteLatest; break; } - this.attributeService.deleteEntityTimeseries(this.entityIdValue, deleteTimeseries, deleteAllDataForKeys, - startTs, endTs, rewriteLatestIfDeleted, deleteLatest) - .subscribe(() => this.reloadAttributes()); + if (tasks.length) { + forkJoin(tasks).subscribe(() => this.reloadAttributes()); + } else { + this.attributeService.deleteEntityTimeseries(this.entityIdValue, deleteTimeseries, deleteAllDataForKeys, + startTs, endTs, rewriteLatestIfDeleted, deleteLatest) + .subscribe(() => this.reloadAttributes()); + } } }); } diff --git a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts index 94c66b3734..df2eb931df 100644 --- a/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/attribute/delete-timeseries-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, Inject, InjectionToken, OnDestroy, OnInit } from '@angular/core'; +import { Component, InjectionToken, OnDestroy, OnInit } from '@angular/core'; import { OverlayRef } from '@angular/cdk/overlay'; import { TimeseriesDeleteStrategy, @@ -27,9 +27,6 @@ import { takeUntil } from 'rxjs/operators'; export const DELETE_TIMESERIES_PANEL_DATA = new InjectionToken('DeleteTimeseriesPanelData'); -export interface DeleteTimeseriesPanelData { - isMultipleDeletion: boolean; -} export interface DeleteTimeseriesPanelResult { strategy: TimeseriesDeleteStrategy; @@ -51,23 +48,13 @@ export class DeleteTimeseriesPanelComponent implements OnInit, OnDestroy { strategiesTranslationsMap = timeseriesDeleteStrategyTranslations; - private multipleDeletionStrategies = new Set([ - TimeseriesDeleteStrategy.DELETE_ALL_DATA, - TimeseriesDeleteStrategy.DELETE_ALL_DATA_EXCEPT_LATEST_VALUE - ]); - private destroy$ = new Subject(); - constructor(@Inject(DELETE_TIMESERIES_PANEL_DATA) private data: DeleteTimeseriesPanelData, - private overlayRef: OverlayRef, + constructor(private overlayRef: OverlayRef, private fb: FormBuilder) { } ngOnInit(): void { const today = new Date(); - if (this.data.isMultipleDeletion) { - this.strategiesTranslationsMap = new Map(Array.from(this.strategiesTranslationsMap) - .filter(([strategy]) => this.multipleDeletionStrategies.has(strategy))) - } this.deleteTimeseriesFormGroup = this.fb.group({ strategy: [TimeseriesDeleteStrategy.DELETE_ALL_DATA], startDateTime: [ From f1804f2fb27e58e13181471397618ec9a07eb174 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Wed, 11 Oct 2023 13:02:51 +0300 Subject: [PATCH 156/267] command whitespaces hotfix --- .../widget/lib/gateway/gateway-configuration.component.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts index c4e1257e64..ef4e946579 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts @@ -409,9 +409,14 @@ export class GatewayConfigurationComponent implements OnInit { const commandsFormArray = this.commandFormArray(); const commandFormGroup = this.fb.group({ attributeOnGateway: [command.attributeOnGateway || null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], - command: [command.command || null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], + command: [command.command || null, [Validators.required]], timeout: [command.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.pattern(/^[^.\s]+$/)]], }); + commandFormGroup.get('command').valueChanges.subscribe(value=>{ + if (value && !(value as String).trim().length) { + commandFormGroup.get('command').setValue("", {emitEvent: false}); + } + }) commandsFormArray.push(commandFormGroup); } From bc20ba7c83da88dadafac0c80439fe34bf42aa9b Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Wed, 11 Oct 2023 16:42:45 +0300 Subject: [PATCH 157/267] command whitespaces hotfix regex solution --- .../lib/gateway/gateway-configuration.component.html | 3 +++ .../widget/lib/gateway/gateway-configuration.component.ts | 7 +------ ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html index b5b995e4d8..7ddf0c8cd9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.html @@ -586,6 +586,9 @@ {{ 'gateway.statistics.command-required' | translate }} + + {{ 'gateway.statistics.command-pattern' | translate }} + info_outlined diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts index ef4e946579..1df76f2716 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-configuration.component.ts @@ -409,14 +409,9 @@ export class GatewayConfigurationComponent implements OnInit { const commandsFormArray = this.commandFormArray(); const commandFormGroup = this.fb.group({ attributeOnGateway: [command.attributeOnGateway || null, [Validators.required, Validators.pattern(/^[^.\s]+$/)]], - command: [command.command || null, [Validators.required]], + command: [command.command || null, [Validators.required, Validators.pattern(/^(?=\S).*\S$/)]], timeout: [command.timeout || null, [Validators.required, Validators.min(1), Validators.pattern(/^-?[0-9]+$/), Validators.pattern(/^[^.\s]+$/)]], }); - commandFormGroup.get('command').valueChanges.subscribe(value=>{ - if (value && !(value as String).trim().length) { - commandFormGroup.get('command').setValue("", {emitEvent: false}); - } - }) commandsFormArray.push(commandFormGroup); } 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 876fb19afb..47528369bb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -2783,6 +2783,7 @@ "attribute-name-required": "Attribute name is required", "command": "Command", "command-required": "Command is required", + "command-pattern": "Command is not valid", "remove": "Remove command" }, "storage": "Storage", From 761c900fc5fe7d3e05f40ec361801671f2372de2 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 11 Oct 2023 17:34:05 +0300 Subject: [PATCH 158/267] added yml parameter description for transport services --- .../src/main/resources/thingsboard.yml | 342 +++++++++--------- tools/src/main/python/check_yml_file.py | 33 +- .../src/main/resources/tb-coap-transport.yml | 149 +++++++- .../src/main/resources/tb-http-transport.yml | 137 ++++++- .../src/main/resources/tb-lwm2m-transport.yml | 161 ++++++++- .../src/main/resources/tb-mqtt-transport.yml | 152 +++++++- .../src/main/resources/tb-snmp-transport.yml | 149 +++++++- 7 files changed, 891 insertions(+), 232 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index b73c4f1fda..c7d5af8a5d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -14,9 +14,9 @@ # limitations under the License. # -# Server common properties +# Server common parameters server: - # Server bind address + # Server bind-address address: "${HTTP_BIND_ADDRESS:0.0.0.0}" # Server bind port port: "${HTTP_BIND_PORT:8080}" @@ -34,7 +34,7 @@ server: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${SSL_PEM_CERT:server.pem}" - # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in the server certificate file; key_file: "${SSL_PEM_KEY:server_key.pem}" # Server certificate private key password (optional) key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" @@ -54,41 +54,41 @@ server: http2: # Enable/disable HTTP/2 support enabled: "${HTTP2_ENABLED:true}" - # Log errors with stacktrace when REST API throws exception with message "Please contact sysadmin" + # Log errors with stacktrace when REST API throws an exception with the message "Please contact sysadmin" log_controller_error_stack_trace: "${HTTP_LOG_CONTROLLER_ERROR_STACK_TRACE:false}" ws: # Timeout for sending data to client WebSocket session in milliseconds send_timeout: "${TB_SERVER_WS_SEND_TIMEOUT:5000}" - # recommended timeout >= 30 seconds. Platform will attempt to send 'ping' request 3 times within the timeout + # recommended timeout >= 30 seconds. The platform will attempt to send a 'ping' request 3 times within the timeout ping_timeout: "${TB_SERVER_WS_PING_TIMEOUT:30000}" dynamic_page_link: # Refresh rate of the dynamic alarm end entity data queries refresh_interval: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_INTERVAL_SEC:60}" # Thread pool size to execute dynamic queries refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" - # Maximum number of dynamic queries per refresh interval. For example, no more than 10 alarm queries executed by user simultaneously in all browsers. + # Maximum number of dynamic queries per refresh interval. For example, no more than 10 alarm queries are executed by the user simultaneously in all browsers. max_alarm_queries_per_refresh_interval: "${TB_SERVER_WS_MAX_ALARM_QUERIES_PER_REFRESH_INTERVAL:10}" - # Maximum number of dynamic queries per user. For example, no more than 10 alarm widgets opened by user simultaneously in all browsers< + # Maximum number of dynamic queries per user. For example, no more than 10 alarm widgets opened by the user simultaneously in all browsers< max_per_user: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_MAX_PER_USER:10}" - # Maximum number of entities returned for single entity subscription. For example, no more than 10 000 entities on the map widget + # Maximum number of entities returned for single entity subscription. For example, no more than 10,000 entities on the map widget max_entities_per_data_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_DATA_SUBSCRIPTION:10000}" - # Maximum number of alarms returned for single alarm subscription. For example, no more than 10 000 alarms on the alarm widget + # Maximum number of alarms returned for single alarm subscription. For example, no more than 10,000 alarms on the alarm widget max_entities_per_alarm_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_ALARM_SUBSCRIPTION:10000}" # Maximum queue size of the websocket updates per session. This restriction prevents infinite updates of WS max_queue_messages_per_session: "${TB_SERVER_WS_DEFAULT_QUEUE_MESSAGES_PER_SESSION:1000}" rest: server_side_rpc: - # Minimum value of the server side RPC timeout. May override value provided in the REST API call. + # Minimum value of the server-side RPC timeout. May override value provided in the REST API call. # Since 2.5 migration to queues, the RPC delay depends on the size of the pending messages in the queue, - # so default UI parameter of 500ms may not be sufficient for loaded environments. + # So default UI parameter of 500ms may not be sufficient for loaded environments. min_timeout: "${MIN_SERVER_SIDE_RPC_TIMEOUT:5000}" - # Default value of the server side RPC timeout. + # Default value of the server-side RPC timeout. default_timeout: "${DEFAULT_SERVER_SIDE_RPC_TIMEOUT:10000}" rate_limits: - # Limit that prohibits resetting the password for the user too often. The value of rate limit. By default, no more than 5 requests per hour + # Limit that prohibits resetting the password for the user too often. The value of the rate limit. By default, no more than 5 requests per hour reset_password_per_user: "${RESET_PASSWORD_PER_USER_RATE_LIMIT_CONFIGURATION:5:3600}" -# Application info +# Application info parameters app: # Application version version: "@project.version@" @@ -107,28 +107,28 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" - # The recalculate_delay property recommended in a microservices architecture setup for rule-engine services. + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" -# Cluster properties +# Cluster parameters cluster: stats: - # Enable/Disable the cluster statistics. Calculates number of messages sent between cluster nodes based on each type + # Enable/Disable the cluster statistics. Calculates the number of messages sent between cluster nodes based on each type enabled: "${TB_CLUSTER_STATS_ENABLED:false}" # Interval of printing the cluster stats to the log file print_interval_ms: "${TB_CLUSTER_STATS_PRINT_INTERVAL_MS:10000}" # Plugins configuration parameters plugins: - # Comma separated package list used during classpath scanning for plugins + # Comma-separated package list used during classpath scanning for plugins scan_packages: "${PLUGINS_SCAN_PACKAGES:org.thingsboard.server.extensions,org.thingsboard.rule.engine}" # Security parameters security: # JWT Token parameters - jwt: # Since 3.4.2 values are persisted to the database during install or upgrade. On Install, the key will be generated randomly if no custom value set. You can change it later from Web UI under SYS_ADMIN + jwt: # Since 3.4.2 values are persisted in the database during installation or upgrade. On Install, the key will be generated randomly if no custom value set. You can change it later from Web UI under SYS_ADMIN tokenExpirationTime: "${JWT_TOKEN_EXPIRATION_TIME:9000}" # Number of seconds (2.5 hours) refreshTokenExpTime: "${JWT_REFRESH_TOKEN_EXPIRATION_TIME:604800}" # Number of seconds (1 week). tokenIssuer: "${JWT_TOKEN_ISSUER:thingsboard.io}" # User JWT Token issuer @@ -138,7 +138,7 @@ security: # Enable/disable case-sensitive username login user_login_case_sensitive: "${SECURITY_USER_LOGIN_CASE_SENSITIVE:true}" claim: - # Enable/disable claiming devices, if false -> the device's [claimingAllowed] SERVER_SCOPE attribute must be set to [true] to allow claiming specific device + # Enable/disable claiming devices; if false -> the device's [claimingAllowed] SERVER_SCOPE attribute must be set to [true] to allow claiming the specific device allowClaimingByDefault: "${SECURITY_CLAIM_ALLOW_CLAIMING_BY_DEFAULT:true}" # Time allowed to claim the device in milliseconds duration: "${SECURITY_CLAIM_DURATION:86400000}" # 1 minute, note this value must equal claimDevices.timeToLiveInMinutes value @@ -157,31 +157,32 @@ security: # The password of the cacerts keystore file password: "${SECURITY_JAVA_CACERTS_PASSWORD:changeit}" +# Mail settings parameters mail: oauth2: - # Interval to check refresh token is going to expire in seconds(by default 1 day). + # Interval to check that the refresh token will expire in seconds(by default, 1 day). refreshTokenCheckingInterval: "${REFRESH_TOKEN_EXPIRATION_CHECKING_INTERVAL:86400}" # Usage statistics parameters usage: stats: report: - # Enable/Disable collection of statistics about API usage. Collected on a system and tenant level by default + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" - # Interval of reporting the statistics. By default, the summarized statistics is sent every 10 seconds + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" check: - # Interval of checking the start of next cycle and re-enabling the blocked tenants/customers + # Interval of checking the start of the next cycle and re-enabling the blocked tenants/customers cycle: "${USAGE_STATS_CHECK_CYCLE:60000}" - # In milliseconds. Default value is 3 minutes + # In milliseconds. The default value is 3 minutes gauge_report_interval: "${USAGE_STATS_GAUGE_REPORT_INTERVAL:180000}" devices: - # In seconds, default value is 1 minutes. When changing, in cluster mode, make sure usage.stats.gauge_report_interval is set to x2-x3 of this value + # In seconds, the default value is 1 minute. When changing, in cluster mode, make sure usage.stats.gauge_report_interval is set to x2-x3 of this value report_interval: "${DEVICES_STATS_REPORT_INTERVAL:60}" -# UI parameters +# UI settings parameters ui: # Dashboard parameters dashboard: @@ -189,14 +190,14 @@ ui: max_datapoints_limit: "${DASHBOARD_MAX_DATAPOINTS_LIMIT:50000}" # Help parameters help: - # Base url for UI help assets + # Base URL for UI help assets base-url: "${UI_HELP_BASE_URL:https://raw.githubusercontent.com/thingsboard/thingsboard-ui-help/release-3.6}" # Database telemetry parameters database: - ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by single API call to fetch telemetry records + ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by a single API call to fetch telemetry records ts: - type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale) + type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra or timescale) ts_latest: type: "${DATABASE_TS_LATEST_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale) @@ -208,24 +209,24 @@ cassandra: keyspace_name: "${CASSANDRA_KEYSPACE_NAME:thingsboard}" # Specify node list url: "${CASSANDRA_URL:127.0.0.1:9042}" - # Specify local datacenter name + # Specify the local data center name local_datacenter: "${CASSANDRA_LOCAL_DATACENTER:datacenter1}" ssl: # Enable/disable secure connection enabled: "${CASSANDRA_USE_SSL:false}" # Enable/disable validation of Cassandra server hostname - # If enabled, hostname of Cassandra server must match CN of server certificate + # If enabled, the hostname of the Cassandra server must match the CN of the server certificate hostname_validation: "${CASSANDRA_SSL_HOSTNAME_VALIDATION:true}" - # Set trust store for client authentication of server (optional, uses trust store from default SSLContext if not set) + # Set trust store for client authentication of the server (optional, uses trust store from default SSLContext if not set) trust_store: "${CASSANDRA_SSL_TRUST_STORE:}" # The password for Cassandra trust store key trust_store_password: "${CASSANDRA_SSL_TRUST_STORE_PASSWORD:}" - # Set key store for server authentication of client (optional, uses key store from default SSLContext if not set) + # Set key store for server authentication of the client (optional, uses key store from default SSLContext if not set) # A key store is only needed if the Cassandra server requires client authentication key_store: "${CASSANDRA_SSL_KEY_STORE:}" - # The password for Cassandra key store + # The password for the Cassandra key store key_store_password: "${CASSANDRA_SSL_KEY_STORE_PASSWORD:}" - # Comma separated list of cipher suites (optional, uses Java default cipher suites if not set) + # Comma-separated list of cipher suites (optional, uses Java default cipher suites if not set) cipher_suites: "${CASSANDRA_SSL_CIPHER_SUITES:}" # Enable/disable JMX jmx: "${CASSANDRA_USE_JMX:false}" @@ -233,9 +234,9 @@ cassandra: metrics: "${CASSANDRA_USE_METRICS:false}" # NONE SNAPPY LZ4 compression: "${CASSANDRA_COMPRESSION:none}" - # Specify cassandra cluster initialization timeout in milliseconds (if no hosts available during startup) + # Specify cassandra cluster initialization timeout in milliseconds (if no hosts are available during startup) init_timeout_ms: "${CASSANDRA_CLUSTER_INIT_TIMEOUT_MS:300000}" - # Specify cassandra claster initialization retry interval (if no hosts available during startup) + # Specify cassandra cluster initialization retry interval (if no hosts available during startup) init_retry_interval_ms: "${CASSANDRA_CLUSTER_INIT_RETRY_INTERVAL_MS:3000}" # Cassandra max local requests per connection max_requests_per_connection_local: "${CASSANDRA_MAX_REQUESTS_PER_CONNECTION_LOCAL:32768}" @@ -258,13 +259,13 @@ cassandra: # Cassandra cluster connection socket parameters # socket: - # Sets the timeout, in millisecond, of a native connection from ThingsBoard to Cassandra. The default value is 5000 + # Sets the timeout, in milliseconds, of a native connection from ThingsBoard to Cassandra. The default value is 5000 connect_timeout: "${CASSANDRA_SOCKET_TIMEOUT:5000}" # Timeout before closing the connection. Value set in milliseconds read_timeout: "${CASSANDRA_SOCKET_READ_TIMEOUT:20000}" # Gets if TCP keep-alive must be used keep_alive: "${CASSANDRA_SOCKET_KEEP_ALIVE:true}" - # Enable/Disable reuse-address.The socket option allows for the reuse of local addresses and ports + # Enable/Disable reuse-address. The socket option allows for the reuse of local addresses and ports reuse_address: "${CASSANDRA_SOCKET_REUSE_ADDRESS:true}" # Sets the linger-on-close timeout. By default, this option is not set by the driver. The actual value will be the default from the underlying Netty transport so_linger: "${CASSANDRA_SOCKET_SO_LINGER:}" @@ -287,9 +288,9 @@ cassandra: ts_key_value_partitioning: "${TS_KV_PARTITIONING:MONTHS}" # Enable/Disable timestamp key-value partioning on read queries use_ts_key_value_partitioning_on_read: "${USE_TS_KV_PARTITIONING_ON_READ:true}" - # The number of partitions that are cached in memory of each service. Useful to decrease load of re-inserting same partitions again + # The number of partitions that are cached in memory of each service. It is useful to decrease the load of re-inserting the same partitions again ts_key_value_partitions_max_cache_size: "${TS_KV_PARTITIONS_MAX_CACHE_SIZE:100000}" - # Timeseries Time To Live (in seconds) for Cassandra Record. 0 - record is never expired + # Timeseries Time To Live (in seconds) for Cassandra Record. 0 - record has never expired ts_key_value_ttl: "${TS_KV_TTL:0}" # Maximum number of Cassandra queries that are waiting for execution buffer_size: "${CASSANDRA_QUERY_BUFFER_SIZE:200000}" @@ -299,13 +300,13 @@ cassandra: permit_max_wait_time: "${PERMIT_MAX_WAIT_TIME:120000}" # Amount of threads to dispatch cassandra queries dispatcher_threads: "${CASSANDRA_QUERY_DISPATCHER_THREADS:2}" - callback_threads: "${CASSANDRA_QUERY_CALLBACK_THREADS:4}" # Buffered rate executor (read, write), for managing I/O rate. See "nosql-*-callback" threads in JMX + callback_threads: "${CASSANDRA_QUERY_CALLBACK_THREADS:4}" # Buffered rate executor (read, write) for managing I/O rate. See "nosql-*-callback" threads in JMX result_processing_threads: "${CASSANDRA_QUERY_RESULT_PROCESSING_THREADS:50}" # Result set transformer and processing. See "cassandra-callback" threads in JMX # Cassandra query queue polling interval in milliseconds poll_ms: "${CASSANDRA_QUERY_POLL_MS:50}" # Interval in milliseconds for printing Cassandra query queue statistic rate_limit_print_interval_ms: "${CASSANDRA_QUERY_RATE_LIMIT_PRINT_MS:10000}" - # set all data types values except target to null for the same ts on save + # set all data type values except target to null for the same ts on save set_null_values_enabled: "${CASSANDRA_QUERY_SET_NULL_VALUES_ENABLED:false}" # log one of cassandra queries with specified frequency (0 - logging is disabled) print_queries_freq: "${CASSANDRA_QUERY_PRINT_FREQ:0}" @@ -318,27 +319,27 @@ sql: # Specify batch size for persisting attribute updates attributes: batch_size: "${SQL_ATTRIBUTES_BATCH_SIZE:1000}" # Batch size for persisting attribute updates - batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:50}" # Max timeout for attributes entries queue polling. Value set in milliseconds + batch_max_delay: "${SQL_ATTRIBUTES_BATCH_MAX_DELAY_MS:50}" # Max timeout for attributes entries queue polling. The value is set in milliseconds stats_print_interval_ms: "${SQL_ATTRIBUTES_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing attributes updates statistic - 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 + batch_threads: "${SQL_ATTRIBUTES_BATCH_THREADS:3}" # batch thread count has to be a prime number like 3 or 5 to gain perfect hash distribution value_no_xss_validation: "${SQL_ATTRIBUTES_VALUE_NO_XSS_VALIDATION:false}" # If true attribute values will be checked for XSS vulnerability ts: batch_size: "${SQL_TS_BATCH_SIZE:10000}" # Batch size for persisting timeseries inserts - batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}" # Max timeout for time-series entries queue polling. Value set in milliseconds + batch_max_delay: "${SQL_TS_BATCH_MAX_DELAY_MS:100}" # Max timeout for time-series entries queue polling. The value set in milliseconds stats_print_interval_ms: "${SQL_TS_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing timeseries insert statistic - 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 + batch_threads: "${SQL_TS_BATCH_THREADS:3}" # batch thread count has to be a prime number like 3 or 5 to gain perfect hash distribution value_no_xss_validation: "${SQL_TS_VALUE_NO_XSS_VALIDATION:false}" # If true telemetry values will be checked for XSS vulnerability ts_latest: batch_size: "${SQL_TS_LATEST_BATCH_SIZE:1000}" # Batch size for persisting latest telemetry updates batch_max_delay: "${SQL_TS_LATEST_BATCH_MAX_DELAY_MS:50}" # Maximum timeout for latest telemetry entries queue polling. The value set in milliseconds stats_print_interval_ms: "${SQL_TS_LATEST_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing latest telemetry updates statistic - 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}" # Update latest values only if the timestamp of the new record is greater or equals than timestamp of the previously saved latest value. Latest values are stored separately from historical values for fast lookup from DB. Insert of historical value happens in any case + batch_threads: "${SQL_TS_LATEST_BATCH_THREADS:3}" # batch thread count has 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}" # Update latest values only if the timestamp of the new record is greater or equals the timestamp of the previously saved latest value. The latest values are stored separately from historical values for fast lookup from DB. Insert of historical value happens in any case events: batch_size: "${SQL_EVENTS_BATCH_SIZE:10000}" # Batch size for persisting latest telemetry updates batch_max_delay: "${SQL_EVENTS_BATCH_MAX_DELAY_MS:100}" # Max timeout for latest telemetry entries queue polling. The value set in milliseconds stats_print_interval_ms: "${SQL_EVENTS_BATCH_STATS_PRINT_MS:10000}" # Interval in milliseconds for printing latest telemetry updates statistic - batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution + batch_threads: "${SQL_EVENTS_BATCH_THREADS:3}" # batch thread count has to be a prime number like 3 or 5 to gain perfect hash distribution partition_size: "${SQL_EVENTS_REGULAR_PARTITION_SIZE_HOURS:168}" # Number of hours to partition the events. The current value corresponds to one week. debug_partition_size: "${SQL_EVENTS_DEBUG_PARTITION_SIZE_HOURS:1}" # Number of hours to partition the debug events. The current value corresponds to one hour. edge_events: @@ -356,13 +357,13 @@ sql: batch_sort: "${SQL_BATCH_SORT:true}" # Specify whether to remove null characters from strValue of attributes and timeseries before insert remove_null_chars: "${SQL_REMOVE_NULL_CHARS:true}" - # Specify whether to log database queries and their parameters generated by entity query repository + # Specify whether to log database queries and their parameters generated by the entity query repository log_queries: "${SQL_LOG_QUERIES:false}" # Threshold of slow SQL queries to log. The value set in milliseconds log_queries_threshold: "${SQL_LOG_QUERIES_THRESHOLD:5000}" # Enable/Disable logging statistic information about tenants log_tenant_stats: "${SQL_LOG_TENANT_STATS:true}" - # Interval in milliseconds for printing latest statistic information about tenant + # Interval in milliseconds for printing the latest statistic information about the tenant log_tenant_stats_interval_ms: "${SQL_LOG_TENANT_STATS_INTERVAL_MS:60000}" postgres: # Specify partitioning size for timestamp key-value storage. Example: DAYS, MONTHS, YEARS, INDEFINITE. @@ -370,7 +371,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:3}" # batch thread count have to be a prime number like 3 or 5 to gain perfect hash distribution + batch_threads: "${SQL_TIMESCALE_BATCH_THREADS:3}" # batch thread count has to be a prime number like 3 or 5 to gain perfect hash distribution ttl: ts: # The parameter to specify whether to use TTL (Time To Live) for timeseries records @@ -381,9 +382,9 @@ sql: # The parameter to specify whether to use TTL (Time To Live) for event records enabled: "${SQL_TTL_EVENTS_ENABLED:true}" execution_interval_ms: "${SQL_TTL_EVENTS_EXECUTION_INTERVAL:3600000}" # Number of milliseconds (max random initial delay and fixed period). - # Number of seconds. TTL is disabled by default. Accuracy of the cleanup depends on the sql.events.partition_size parameter. + # Number of seconds. TTL is disabled by default. The accuracy of the cleanup depends on the sql.events.partition_size parameter. events_ttl: "${SQL_TTL_EVENTS_EVENTS_TTL:0}" - # Number of seconds. The current value corresponds to one week. Accuracy of the cleanup depends on the sql.events.debug_partition_size parameter. + # Number of seconds. The current value corresponds to one week. The accuracy of the cleanup depends on the sql.events.debug_partition_size parameter. debug_events_ttl: "${SQL_TTL_EVENTS_DEBUG_EVENTS_TTL:604800}" edge_events: enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for egde event records @@ -397,33 +398,33 @@ sql: checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours audit_logs: enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for audit log records - ttl: "${SQL_TTL_AUDIT_LOGS_SECS:0}" # Disabled by default. Accuracy of the cleanup depends on the sql.audit_logs.partition_size + ttl: "${SQL_TTL_AUDIT_LOGS_SECS:0}" # Disabled by default. The accuracy of the cleanup depends on the sql.audit_logs.partition_size checking_interval_ms: "${SQL_TTL_AUDIT_LOGS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day notifications: enabled: "${SQL_TTL_NOTIFICATIONS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for notification center records ttl: "${SQL_TTL_NOTIFICATIONS_SECS:2592000}" # Default value - 30 days checking_interval_ms: "${SQL_TTL_NOTIFICATIONS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day relations: - max_level: "${SQL_RELATIONS_MAX_LEVEL:50}" # This value has to be reasonable small to prevent infinite recursion as early as possible - pool_size: "${SQL_RELATIONS_POOL_SIZE:4}" # This value has to be reasonable small to prevent relation query blocking all other DB calls - query_timeout: "${SQL_RELATIONS_QUERY_TIMEOUT_SEC:20}" # This value has to be reasonable small to prevent relation query blocking all other DB calls + max_level: "${SQL_RELATIONS_MAX_LEVEL:50}" # This value has to be reasonably small to prevent infinite recursion as early as possible + pool_size: "${SQL_RELATIONS_POOL_SIZE:4}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls + query_timeout: "${SQL_RELATIONS_QUERY_TIMEOUT_SEC:20}" # This value has to be reasonably small to prevent the relation query from blocking all other DB calls # Actor system parameters actors: system: - throughput: "${ACTORS_SYSTEM_THROUGHPUT:5}" # Number of messages the actor system will process per actor before switching to processing of messages for next actor + throughput: "${ACTORS_SYSTEM_THROUGHPUT:5}" # Number of messages the actor system will process per actor before switching to processing of messages for the next actor scheduler_pool_size: "${ACTORS_SYSTEM_SCHEDULER_POOL_SIZE:1}" # Thread pool size for actor system scheduler max_actor_init_attempts: "${ACTORS_SYSTEM_MAX_ACTOR_INIT_ATTEMPTS:10}" # Maximum number of attempts to init the actor before disabling the actor app_dispatcher_pool_size: "${ACTORS_SYSTEM_APP_DISPATCHER_POOL_SIZE:1}" # Thread pool size for main actor system dispatcher tenant_dispatcher_pool_size: "${ACTORS_SYSTEM_TENANT_DISPATCHER_POOL_SIZE:2}" # Thread pool size for actor system dispatcher that process messages for tenant actors device_dispatcher_pool_size: "${ACTORS_SYSTEM_DEVICE_DISPATCHER_POOL_SIZE:4}" # Thread pool size for actor system dispatcher that process messages for device actors - rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:8}" # Thread pool size for actor system dispatcher that process messages for rule engine (chain/node) actors + rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:8}" # Thread pool size for actor system dispatcher that processes messages for rule engine (chain/node) actors tenant: create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" # Create components in initialization session: max_concurrent_sessions_per_device: "${ACTORS_MAX_CONCURRENT_SESSION_PER_DEVICE:1}" # Max number of concurrent sessions per device sync: - # Default timeout for processing request using synchronous session (HTTP, CoAP) in milliseconds + # Default timeout for processing requests using synchronous session (HTTP, CoAP) in milliseconds timeout: "${ACTORS_SESSION_SYNC_TIMEOUT:10000}" rule: # Specify thread pool size for database request callbacks executor service @@ -441,7 +442,7 @@ actors: # Specify thread pool size for external call service external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:50}" chain: - # Errors for particular actor are persisted once per specified amount of milliseconds + # Errors for particular actors are persisted once per specified amount of milliseconds error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" debug_mode_rate_limits_per_tenant: # Enable/Disable the rate limit of persisted debug events for all rule nodes per tenant @@ -452,20 +453,20 @@ actors: # Errors for particular actor are persisted once per specified amount of milliseconds error_persist_frequency: "${ACTORS_RULE_NODE_ERROR_FREQUENCY:3000}" transaction: - # Size of queues which store messages for transaction rule nodes + # Size of queues that store messages for transaction rule nodes queue_size: "${ACTORS_RULE_TRANSACTION_QUEUE_SIZE:15000}" # Time in milliseconds for transaction to complete duration: "${ACTORS_RULE_TRANSACTION_DURATION:60000}" external: - # Force acknowledgement of the incoming message for external rule nodes to decrease processing latency. + # Force acknowledgment of the incoming message for external rule nodes to decrease processing latency. # Enqueue the result of external node processing as a separate message to the rule engine. force_ack: "${ACTORS_RULE_EXTERNAL_NODE_FORCE_ACK:false}" rpc: - # Maximum number of persistent RPC call retries in case of failed requests delivery. + # Maximum number of persistent RPC call retries in case of failed request delivery. max_retries: "${ACTORS_RPC_MAX_RETRIES:5}" # RPC submit strategies. Allowed values: BURST, SEQUENTIAL_ON_ACK_FROM_DEVICE, SEQUENTIAL_ON_RESPONSE_FROM_DEVICE. submit_strategy: "${ACTORS_RPC_SUBMIT_STRATEGY_TYPE:BURST}" - # Time in milliseconds for RPC to receive response after delivery. Used only for SEQUENTIAL_ON_RESPONSE_FROM_DEVICE submit strategy. + # Time in milliseconds for RPC to receive a response after delivery. Used only for SEQUENTIAL_ON_RESPONSE_FROM_DEVICE submit strategy. response_timeout_ms: "${ACTORS_RPC_RESPONSE_TIMEOUT_MS:30000}" statistics: # Enable/disable actor statistics @@ -479,9 +480,9 @@ actors: cache: # caffeine or redis type: "${CACHE_TYPE:caffeine}" - maximumPoolSize: "${CACHE_MAXIMUM_POOL_SIZE:16}" # max pool size to process futures that calls the external cache + maximumPoolSize: "${CACHE_MAXIMUM_POOL_SIZE:16}" # max pool size to process futures that call the external cache attributes: - # make sure that if cache.type is 'redis' and cache.attributes.enabled is 'true' that you change 'maxmemory-policy' Redis config property to 'allkeys-lru', 'allkeys-lfu' or 'allkeys-random' + # make sure that if cache.type is 'redis' and cache.attributes.enabled is 'true' if you change 'maxmemory-policy' Redis config property to 'allkeys-lru', 'allkeys-lfu' or 'allkeys-random' enabled: "${CACHE_ATTRIBUTES_ENABLED:true}" specs: relations: @@ -534,7 +535,7 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_ATTRIBUTES_TTL:1440}" # Attributes cache TTL maxSize: "${CACHE_SPECS_ATTRIBUTES_MAX_SIZE:100000}" # 0 means the cache is disabled userSessionsInvalidation: - # The value of this TTL is ignored and replaced by JWT refresh token expiration time + # The value of this TTL is ignored and replaced by the JWT refresh token expiration time timeToLiveInMinutes: "0" maxSize: "${CACHE_SPECS_USERS_UPDATE_TIME_MAX_SIZE:10000}" # 0 means the cache is disabled otaPackages: @@ -574,7 +575,7 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_ALARM_TYPES_TTL:60}" # Alarm types cache TTL maxSize: "${CACHE_SPECS_ALARM_TYPES_MAX_SIZE:10000}" # 0 means the cache is disabled - # deliberately placed outside 'specs' group above + # deliberately placed outside the 'specs' group above notificationRules: timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}" # notification rules cache TTL maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:1000}" # 0 means the cache is disabled @@ -582,10 +583,10 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_RATE_LIMITS_TTL:120}" # Rate limits cache TTL maxSize: "${CACHE_SPECS_RATE_LIMITS_MAX_SIZE:200000}" # 0 means the cache is disabled -# Spring data properties +# Spring data parameters spring.data.redis.repositories.enabled: false # Disable this because it is not required. -# Redis configuration properties +# Redis configuration parameters redis: # standalone or cluster or sentinel connection: @@ -596,15 +597,15 @@ redis: host: "${REDIS_HOST:localhost}" # Redis connection port port: "${REDIS_PORT:6379}" - # Use default Redis configuration file + # Use the default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" - # this value may be used only if you used not default ClientConfig + # 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 + # 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 + # 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 + # 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. @@ -614,7 +615,7 @@ redis: # if set false will be used pool config build from values of the pool config section useDefaultPoolConfig: "${REDIS_USE_DEFAULT_POOL_CONFIG:true}" sentinel: - # name of master node + # name of the master node master: "${REDIS_MASTER:}" # comma-separated list of "host:port" pairs of sentinels sentinels: "${REDIS_SENTINELS:}" @@ -634,13 +635,13 @@ redis: maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" - # Enable/Disable PING command send when a connection is borrowed + # Enable/Disable PING command sent when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" - # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds + # Minimum time that an idle connection should be idle before it can be evicted from the connection pool. The value is set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" @@ -648,22 +649,23 @@ redis: maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" - # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration + # Determines the behavior when a thread requests a connection from the pool, but there are no available connections, and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" - # TTL for short-living SET commands that are used to replace DEL in order to enable transaction support + # TTL for short-living SET commands that are used to replace DEL to enable transaction support evictTtlInMs: "${REDIS_EVICT_TTL_MS:60000}" -# Update version properties + +# Update version parameters updates: - # Enable/disable checks for new version + # Enable/disable checks for the new version enabled: "${UPDATES_ENABLED:true}" -# Spring CORS configuration +# Spring CORS configuration parameters spring.mvc.cors: mappings: # Intercept path "[/api/**]": - #Comma-separated list of origins to allow. '*' allows all origins. When not set,CORS support is disabled. + #Comma-separated list of origins to allow. '*' allows all origins. When not set, CORS support is disabled. allowed-origin-patterns: "*" #Comma-separated list of methods to allow. '*' allows all methods. allowed-methods: "*" @@ -674,8 +676,8 @@ spring.mvc.cors: #Set whether credentials are supported. When not set, credentials are not supported. allow-credentials: "true" -# General spring properties -spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed or not. +# General spring parameters +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. spring.freemarker.checkTemplateLocation: "false" # spring freemarker configuration spring.mvc.async.request-timeout: "${SPRING_MVC_ASYNC_REQUEST_TIMEOUT:30000}" # The default timeout for asynchronous requests in milliseconds spring.mvc.pathmatch.matching-strategy: "ANT_PATH_MATCHER" # For endpoints matching in Swagger @@ -691,7 +693,7 @@ spring.servlet.multipart.max-request-size: "50MB" # Total request size for a mul spring.jpa.properties.hibernate.jdbc.lob.non_contextual_creation: "true" #Fix Postgres JPA Error (Method org.postgresql.jdbc.PgConnection.createClob() is not yet implemented) spring.jpa.properties.hibernate.order_by.default_null_ordering: "${SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING:last}" # Note: as for current Spring JPA version, custom NullHandling for the Sort.Order is ignored and this parameter is used -# SQL DAO Configuration +# SQL DAO Configuration parameters spring: data: jpa: @@ -716,7 +718,7 @@ spring: hikari: # This property controls the amount of time that a connection can be out of the pool before a message is logged indicating a possible connection leak. A value of 0 means leak detection is disabled leakDetectionThreshold: "${SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD:0}" - # This property allows the number of connections in the pool to increase as demand increases. At the same time, the property ensures that the pool doesn't grow to the point of exhausting a system's resources, which ultimately affects an application's performance and availability + # This property increases the number of connections in the pool as demand increases. At the same time, the property ensures that the pool doesn't grow to the point of exhausting a system's resources, which ultimately affects an application's performance and availability maximumPoolSize: "${SPRING_DATASOURCE_MAXIMUM_POOL_SIZE:16}" registerMbeans: "${SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS:false}" # true - enable MBean to diagnose pools state via JMX @@ -746,12 +748,12 @@ audit-log: sink: # Type of external sink. possible options: none, elasticsearch type: "${AUDIT_LOG_SINK_TYPE:none}" - # Name of the index where audit logs stored + # Name of the index where audit logs are stored # Index name could contain next placeholders (not mandatory): # @{TENANT} - substituted by tenant ID # @{DATE} - substituted by current date in format provided in audit_log.sink.date_format index_pattern: "${AUDIT_LOG_SINK_INDEX_PATTERN:@{TENANT}_AUDIT_LOG_@{DATE}}" - # Date format. Details of the pattern could be found here: + # Date format. Details of the pattern can be found here: # https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html date_format: "${AUDIT_LOG_SINK_DATE_FORMAT:YYYY.MM.dd}" scheme_name: "${AUDIT_LOG_SINK_SCHEME_NAME:http}" # http or https @@ -760,26 +762,26 @@ audit-log: user_name: "${AUDIT_LOG_SINK_USER_NAME:}" # Username used to access external sink system password: "${AUDIT_LOG_SINK_PASSWORD:}" # Password used to access external sink system -# State properties +# Device state parameters state: # Should be greater than transport.sessions.report_timeout defaultInactivityTimeoutInSec: "${DEFAULT_INACTIVITY_TIMEOUT:600}" - defaultStateCheckIntervalInSec: "${DEFAULT_STATE_CHECK_INTERVAL:60}" # Interval for checking the device state after a specified period of time. Time in seconds - # Controls whether we store device 'active' flag in attributes (default) or telemetry. + defaultStateCheckIntervalInSec: "${DEFAULT_STATE_CHECK_INTERVAL:60}" # Interval for checking the device state after a specified period. Time in seconds + # Controls whether we store the device 'active' flag in attributes (default) or telemetry. # If you device to change this parameter, you should re-create the device info view as one of the following: # If 'persistToTelemetry' is changed from 'false' to 'true': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_ts_view;' # If 'persistToTelemetry' is changed from 'true' to 'false': 'CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view;' persistToTelemetry: "${PERSIST_STATE_TO_TELEMETRY:false}" -# Tbel properties +# Tbel parameters tbel: # Enable/Disable TBEL feature. enabled: "${TBEL_ENABLED:true}" - # Limit on the number of arguments that are passed to the function to execute the script + # Limit the number of arguments that are passed to the function to execute the script max_total_args_size: "${TBEL_MAX_TOTAL_ARGS_SIZE:100000}" # Maximum allowed symbols in a result after processing a script max_result_size: "${TBEL_MAX_RESULT_SIZE:300000}" - # Maximum allowed symbols in script body + # Maximum allowed symbols in the script body max_script_body_size: "${TBEL_MAX_SCRIPT_BODY_SIZE:50000}" # Maximum allowed TBEL script execution memory max_memory_limit_mb: "${TBEL_MAX_MEMORY_LIMIT_MB: 8}" @@ -799,11 +801,11 @@ tbel: # Interval of logging for TBEL stats print_interval_ms: "${TB_TBEL_STATS_PRINT_INTERVAL_MS:10000}" -# JS properties +# JS parameters js: # local (Nashorn Engine, deprecated) OR remote JS-Executors (NodeJS) evaluator: "${JS_EVALUATOR:local}" - # Limit on the number of arguments that are passed to the function to execute the script + # Limit the number of arguments that are passed to the function to execute the script max_total_args_size: "${JS_MAX_TOTAL_ARGS_SIZE:100000}" # Maximum allowed symbols in a result after processing a script max_result_size: "${JS_MAX_RESULT_SIZE:300000}" @@ -844,10 +846,10 @@ js: # Interval of logging for remote JS executor stats print_interval_ms: "${TB_JS_REMOTE_STATS_PRINT_INTERVAL_MS:10000}" -# Transport configuration properties +# Transport configuration parameters transport: sessions: - # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if device sends any message, including keepalive messages + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if the device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" @@ -867,7 +869,7 @@ transport: # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" rate_limits: - # Enable or disable generic rate limits. Device and Tenant specific rate limits are controlled in Tenant Profile. + # Enable or disable generic rate limits. Device and Tenant-specific rate limits are controlled in Tenant Profile. ip_limits_enabled: "${TB_TRANSPORT_IP_RATE_LIMITS_ENABLED:false}" # Maximum number of connect attempts with invalid credentials max_wrong_credentials_per_ip: "${TB_TRANSPORT_MAX_WRONG_CREDENTIALS_PER_IP:10}" @@ -885,7 +887,7 @@ transport: mqtt: # Enable/disable mqtt transport protocol. enabled: "${MQTT_ENABLED:true}" - # MQTT bind address + # MQTT bind-address bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" # MQTT bind port bind_port: "${MQTT_BIND_PORT:1883}" @@ -910,7 +912,7 @@ transport: ssl: # Enable/disable SSL support enabled: "${MQTT_SSL_ENABLED:false}" - # MQTT SSL bind address + # MQTT SSL bind-address bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}" # MQTT SSL bind port bind_port: "${MQTT_SSL_BIND_PORT:8883}" @@ -946,7 +948,7 @@ transport: coap: # Enable/disable coap transport protocol. enabled: "${COAP_ENABLED:true}" - # CoAP bind address + # CoAP bind-address bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" # CoAP bind port bind_port: "${COAP_BIND_PORT:5683}" @@ -963,7 +965,7 @@ transport: enabled: "${COAP_DTLS_ENABLED:false}" # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 retransmission_timeout: "${COAP_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" - # CoAP DTLS bind address + # CoAP DTLS bind-address bind_address: "${COAP_DTLS_BIND_ADDRESS:0.0.0.0}" # CoAP DTLS bind port bind_port: "${COAP_DTLS_BIND_PORT:5684}" @@ -975,7 +977,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${COAP_DTLS_PEM_CERT:coapserver.pem}" - # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in the server certificate file; key_file: "${COAP_DTLS_PEM_KEY:coapserver_key.pem}" # Server certificate private key password (optional) key_password: "${COAP_DTLS_PEM_KEY_PASSWORD:server_key_password}" @@ -994,7 +996,7 @@ transport: x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" - # Inactivity timeout of DTLS session. Used to cleanup cache + # Inactivity timeout of DTLS session. Used to clean cache dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" # Interval of periodic eviction of the timed-out DTLS sessions dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" @@ -1027,7 +1029,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_SERVER_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in the server certificate file; key_file: "${LWM2M_SERVER_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_SERVER_PEM_KEY_PASSWORD:server_key_password}" @@ -1120,7 +1122,7 @@ transport: clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" # Maximum log size log_max_length: "${LWM2M_LOG_MAX_LENGTH:1024}" - # PSM Activity Timer if not specified in device profile + # PSM Activity Timer if not specified in the device profile psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" # Paging Transmission Window for eDRX support if not specified in the device profile paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" @@ -1137,63 +1139,63 @@ transport: parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}" # to configure SNMP to work over UDP or TCP underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}" - # Batch size to request OID mappings from device (useful when device profile has multiple hundreds of OID mappings) + # Batch size to request OID mappings from the device (useful when the device profile has multiple hundreds of OID mappings) max_request_oids: "${SNMP_MAX_REQUEST_OIDS:100}" response: - # To ignore SNMP response values that do not match data type of the configured OID mapping (by default false - will throw error if any value of the response not matches configured data types) + # To ignore SNMP response values that do not match the data type of the configured OID mapping (by default false - will throw an error if any value of the response not match configured data types) ignore_type_cast_errors: "${SNMP_RESPONSE_IGNORE_TYPE_CAST_ERRORS:false}" stats: - # Enable/Disable collection of transport statistics + # Enable/Disable the collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" -# Device connectivity properties to publish telemetry +# Device connectivity parameters device: connectivity: http: # If true check-connectivity service will include curl command to the list of all test commands using DEVICE_CONNECTIVITY_HTTP_HOST and DEVICE_CONNECTIVITY_HTTP_PORT variables enabled: "${DEVICE_CONNECTIVITY_HTTP_ENABLED:true}" - # Host of http transport service. If empty base url will be used. + # Host of http transport service. If empty, the base URL will be used. host: "${DEVICE_CONNECTIVITY_HTTP_HOST:}" - # Port of http transport service. If empty default http port will be used. + # Port of http transport service. If empty, default http port will be used. port: "${DEVICE_CONNECTIVITY_HTTP_PORT:8080}" https: # If true check-connectivity service will include curl command to the list of all test commands using DEVICE_CONNECTIVITY_HTTPS_HOST and DEVICE_CONNECTIVITY_HTTPS_PORT variables enabled: "${DEVICE_CONNECTIVITY_HTTPS_ENABLED:false}" - # Host of http transport service. If empty base url will be used. + # Host of http transport service. If empty, the base URL will be used. host: "${DEVICE_CONNECTIVITY_HTTPS_HOST:}" - # Port of http transport service. If empty default https port will be used. + # Port of http transport service. If empty, the default https port will be used. port: "${DEVICE_CONNECTIVITY_HTTPS_PORT:443}" mqtt: # If true mosquito command will be included to the list of all test commands using DEVICE_CONNECTIVITY_MQTT_HOST and DEVICE_CONNECTIVITY_MQTT_PORT enabled: "${DEVICE_CONNECTIVITY_MQTT_ENABLED:true}" - # Host of mqtt transport service. If empty base url host will be used. + # Host of mqtt transport service. If empty, the base url host will be used. host: "${DEVICE_CONNECTIVITY_MQTT_HOST:}" # Port of mqtt transport service port: "${DEVICE_CONNECTIVITY_MQTT_PORT:1883}" mqtts: - # If true mosquito command will be included to the list of all test commands using DEVICE_CONNECTIVITY_MQTTS_HOST and DEVICE_CONNECTIVITY_MQTTS_PORT< + # If true mosquito command will be included in the list of all test commands using DEVICE_CONNECTIVITY_MQTTS_HOST and DEVICE_CONNECTIVITY_MQTTS_PORT< enabled: "${DEVICE_CONNECTIVITY_MQTTS_ENABLED:false}" - # Host of mqtt transport service. If empty base url host will be used. + # Host of mqtt transport service. If empty, the base URL host will be used. host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" - # Port of mqtt transport service. If empty default port for mqtts will be used. + # Port of mqtt transport service. If empty, the default port for mqtts will be used. port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" # Path to the server certificate file pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:mqttserver.pem}" coap: - # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. + # If true coap command will be included in the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" - # Host of coap transport service. If empty base url host will be used. + # Host of coap transport service. If empty, the base URL host will be used. host: "${DEVICE_CONNECTIVITY_COAP_HOST:}" - # Port of coap transport service. If empty default port for coap will be used. + # Port of coap transport service. If empty, the default port for coap will be used. port: "${DEVICE_CONNECTIVITY_COAP_PORT:5683}" coaps: - # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAPS_HOST and DEVICE_CONNECTIVITY_COAPS_PORT. + # If true coap command will be included in the list of all test commands using DEVICE_CONNECTIVITY_COAPS_HOST and DEVICE_CONNECTIVITY_COAPS_PORT. enabled: "${DEVICE_CONNECTIVITY_COAPS_ENABLED:false}" - # Host of coap transport service. If empty base url host will be used. + # Host of coap transport service. If empty, the base URL host will be used. host: "${DEVICE_CONNECTIVITY_COAPS_HOST:}" - # Port of coap transport service. If empty default port for coaps will be used. + # Port of coap transport service. If empty, the default port for coaps will be used. port: "${DEVICE_CONNECTIVITY_COAPS_PORT:5684}" # Edges parameters @@ -1203,47 +1205,47 @@ edges: rpc: # RPC port bind port: "${EDGES_RPC_PORT:7070}" - # Maximum time of keep alive client RPC connection. Time in seconds + # Maximum time of keeping alive client RPC connection. Time in seconds client_max_keep_alive_time_sec: "${EDGES_RPC_CLIENT_MAX_KEEP_ALIVE_TIME_SEC:1}" - # Maximum time of keep alive connection. Time in seconds + # Maximum time of keep-alive connection. Time in seconds keep_alive_time_sec: "${EDGES_RPC_KEEP_ALIVE_TIME_SEC:10}" # Timeout of keep alive RPC connection. Time in seconds keep_alive_timeout_sec: "${EDGES_RPC_KEEP_ALIVE_TIMEOUT_SEC:5}" ssl: # Enable/disable SSL support enabled: "${EDGES_RPC_SSL_ENABLED:false}" - # Cert file to be used during TLS connectivity to cloud + # Cert file to be used during TLS connectivity to the cloud cert: "${EDGES_RPC_SSL_CERT:certChainFile.pem}" # Private key file associated with the Cert certificate. This key is used in the encryption process during a secure connection private_key: "${EDGES_RPC_SSL_PRIVATE_KEY:privateKeyFile.pem}" - # Maximum size (in bytes) of inbound messages that cloud can handle from edge. By default, it can handle messages up to 4 Megabytes + # Maximum size (in bytes) of inbound messages the cloud can handle from the edge. By default, it can handle messages up to 4 Megabytes max_inbound_message_size: "${EDGES_RPC_MAX_INBOUND_MESSAGE_SIZE:4194304}" storage: - # Max records of edge event to read from DB and sent to edge + # Max records of edge event to read from DB and sent to the edge max_read_records_count: "${EDGES_STORAGE_MAX_READ_RECORDS_COUNT:50}" - # Number of milliseconds to wait before next check of edge events in DB + # Number of milliseconds to wait before the next check of edge events in DB no_read_records_sleep: "${EDGES_NO_READ_RECORDS_SLEEP:1000}" - # Number of milliseconds to wait before resend failed batch of edge events to edge + # Number of milliseconds to wait before resending failed batch of edge events to edge sleep_between_batches: "${EDGES_SLEEP_BETWEEN_BATCHES:10000}" - # Number of threads that used to check DB for edge events + # Number of threads that are used to check DB for edge events scheduler_pool_size: "${EDGES_SCHEDULER_POOL_SIZE:1}" # Number of threads that used to send downlink messages to edge over gRPC send_scheduler_pool_size: "${EDGES_SEND_SCHEDULER_POOL_SIZE:1}" - # Number of threads that used to convert edge events from DB into downlink message and send them for delivery + # Number of threads that are used to convert edge events from DB into downlink messages and send them for delivery grpc_callback_thread_pool_size: "${EDGES_GRPC_CALLBACK_POOL_SIZE:1}" state: # Persist state of edge (active, last connect, last disconnect) into timeseries or attributes tables. 'false' means to store edge state into attributes table persistToTelemetry: "${EDGES_PERSIST_STATE_TO_TELEMETRY:false}" -# Swagger common properties +# Swagger common parameters swagger: - # If false swagger api docs will be unavailable + # If false swagger API docs will be unavailable enabled: "${SWAGGER_ENABLED:true}" - # General swagger match pattern of swaggerUI links + # General swagger match pattern of swagger UI links api_path_regex: "${SWAGGER_API_PATH_REGEX:/api/.*}" - # General swagger match pattern path of swaggerUI links + # General swagger match pattern path of swagger UI links security_path_regex: "${SWAGGER_SECURITY_PATH_REGEX:/api/.*}" - # Non security API path match pattern of swaggerUI links + # Nonsecurity API path match pattern of swagger UI links non_security_path_regex: "${SWAGGER_NON_SECURITY_PATH_REGEX:/api/(?:noauth|v1)/.*}" # The title on the API doc UI page title: "${SWAGGER_TITLE:ThingsBoard REST API}" @@ -1281,9 +1283,9 @@ queue: truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" - # The location of the key store file. This is optional for client and can be used for two-way authentication for client + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" - # The store password for the key store file. This is optional for client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" @@ -1319,9 +1321,9 @@ queue: # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: - # The endpoint identification algorithm used by clients to validate server host name. The default value is https + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" - # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as transport layer to ensure that clear passwords are not transmitted on the wire without encryption + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" @@ -1344,7 +1346,7 @@ queue: # - key: max.poll.records # value: "${TB_QUEUE_KAFKA_SQ_MAX_POLL_RECORDS:1024}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" - other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside + other: # DEPRECATED. In this section, you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside # - key: "request.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms # value: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms @@ -1372,7 +1374,7 @@ queue: # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" aws_sqs: - # Use default credentials provider for AWS SQS + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" @@ -1405,20 +1407,20 @@ queue: service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" # Message size for PubSub queue.Value in bytes max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" - # Number of messages per a consumer + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: - # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consume again + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consumed again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" - # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consume again + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" - # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consume again + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consumed again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" - # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consume again + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" # PubSub queue properties js-executor: "${TB_QUEUE_PUBSUB_JE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" - # Pub/Sub properties for Transport Api subscribers, messages which will commit after ackDeadlineInSec period can be consume again + # Pub/Sub properties for Transport Api subscribers, messages which will commit after ackDeadlineInSec period can be consumed again version-control: "${TB_QUEUE_PUBSUB_VC_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: # Azure namespace @@ -1447,7 +1449,7 @@ queue: exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" - # RabbitMQ host used to establish connection + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" @@ -1503,11 +1505,11 @@ queue: ota: # Default topic name for OTA updates topic: "${TB_QUEUE_CORE_OTA_TOPIC:tb_ota_package}" - # The interval of processing the OTA updates for devices. Used to avoid any harm to network due to many parallel OTA updates + # The interval of processing the OTA updates for devices. Used to avoid any harm to the network due to many parallel OTA updates pack-interval-ms: "${TB_QUEUE_CORE_OTA_PACK_INTERVAL_MS:60000}" # The size of OTA updates notifications fetched from the queue. The queue stores pairs of firmware and device ids pack-size: "${TB_QUEUE_CORE_OTA_PACK_SIZE:100}" - # Default topic name for queue Kafka, RabbitMQ, etc. + # Stats topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: # Enable/disable statistics for Core microservices @@ -1521,7 +1523,7 @@ queue: partitions: "${TB_QUEUE_VC_PARTITIONS:10}" # Interval in milliseconds between polling of the messages if no new messages arrive poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" - # Timeout before retry all failed and timed-out messages from processing pack + # Timeout before retrying all failed and timed-out messages from the processing pack pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:180000}" # Timeout for a request to VC-executor (for a request for the version of the entity, for a commit charge, etc.) request-timeout: "${TB_QUEUE_VC_REQUEST_TIMEOUT:180000}" @@ -1543,7 +1545,7 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: - # Deprecated. Will be removed in nearest releases + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" @@ -1554,7 +1556,7 @@ queue: enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" - # Max length of error message that is printed by statistics + # Max length of the error message that is printed by statistics max-error-message-length: "${TB_QUEUE_RULE_ENGINE_MAX_ERROR_MESSAGE_LENGTH:4096}" queues: - name: "${TB_QUEUE_RE_MAIN_QUEUE_NAME:Main}" # queue name @@ -1571,7 +1573,7 @@ queue: type: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_TYPE:SKIP_ALL_FAILURES}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT # 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; + failure-percentage: "${TB_QUEUE_RE_MAIN_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less than 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. - name: "${TB_QUEUE_RE_HP_QUEUE_NAME:HighPriority}" # queue name @@ -1588,7 +1590,7 @@ queue: type: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT # 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; + failure-percentage: "${TB_QUEUE_RE_HP_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less than 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. - name: "${TB_QUEUE_RE_SQ_QUEUE_NAME:SequentialByOriginator}" # queue name @@ -1605,13 +1607,13 @@ queue: type: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_TYPE:RETRY_FAILED_AND_TIMED_OUT}" # SKIP_ALL_FAILURES, SKIP_ALL_FAILURES_AND_TIMED_OUT, RETRY_ALL, RETRY_FAILED, RETRY_TIMED_OUT, RETRY_FAILED_AND_TIMED_OUT # 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; + failure-percentage: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_FAILURE_PERCENTAGE:0}" # Skip retry if failures or timeouts are less than 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. - # After a queue is deleted (or profile's isolation option was disabled), Rule Engine will continue reading related topics during this period, before deleting the actual topics + # After a queue is deleted (or the profile's isolation option was disabled), Rule Engine will continue reading related topics during this period before deleting the actual topics topic-deletion-delay: "${TB_QUEUE_RULE_ENGINE_TOPIC_DELETION_DELAY_SEC:30}" transport: - # For high priority notifications that require minimum latency and processing time + # For high-priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" @@ -1628,8 +1630,8 @@ service: # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" rule_engine: - # Comma-separated list of tenant profiles ids assigned to this Rule Engine. - # This Rule Engine will only be responsible for tenants with these profiles (in case 'isolation' option is enabled in profile). + # Comma-separated list of tenant profile ids assigned to this Rule Engine. + # This Rule Engine will only be responsible for tenants with these profiles (in case 'isolation' option is enabled in the profile). assigned_tenant_profiles: "${TB_RULE_ENGINE_ASSIGNED_TENANT_PROFILES:}" # Metrics parameters diff --git a/tools/src/main/python/check_yml_file.py b/tools/src/main/python/check_yml_file.py index 606b456491..0aca5e41af 100644 --- a/tools/src/main/python/check_yml_file.py +++ b/tools/src/main/python/check_yml_file.py @@ -17,13 +17,14 @@ import sys import re + def extract_properties_with_comments(yaml_file_path): properties = {} with open(yaml_file_path, 'r') as file: lines = file.readlines() index = 0 - key_level_map = {0 : ''} + key_level_map = {0: ''} parse_line('', '', key_level_map, 0, index, lines, properties) return properties @@ -42,7 +43,7 @@ def parse_line(table_name, comment, key_level_map, parent_line_level, index, lin # if line is a comment - save comment and parse next line else: if line_level == 0: - key_level_map = {0 : ''} + key_level_map = {0: ''} if line.startswith('#'): if line_level == 0: table_name = line.lstrip('#') @@ -100,11 +101,7 @@ def check_descriptions(properties): return variables_without_description -if __name__ == '__main__': - sys. setrecursionlimit(10000) - # path to the YAML file - input_yaml_file = "application/src/main/resources/thingsboard.yml" - +def check_yml(total_list, input_yaml_file): # Parse yml file to map where key is property key path with '.' separator # and value is an object (env_name_with_default_value, comment, table_name) properties = extract_properties_with_comments(input_yaml_file) @@ -112,11 +109,25 @@ if __name__ == '__main__': # Extract property information (extract env name, default value and comment nearby property) property_info = extract_property_info(properties) - # Check all properies have descriptions - variables_without_desc = check_descriptions(property_info) + # Check all properties have descriptions + variables_without_description = check_descriptions(property_info) + total_list.extend(variables_without_description) + if len(variables_without_description) > 0: + print(f"Check {input_yaml_file}. There are some yml properties without valid description: (total {len(variables_without_description)}) {variables_without_description}.") + +if __name__ == '__main__': + sys.setrecursionlimit(10000) + files_to_check = ["application/src/main/resources/thingsboard.yml", + "transport/http/src/main/resources/tb-http-transport.yml", + "transport/mqtt/src/main/resources/tb-mqtt-transport.yml", + "transport/coap/src/main/resources/tb-coap-transport.yml", + "transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml", + "transport/snmp/src/main/resources/tb-snmp-transport.yml"] - if len(variables_without_desc) > 0: - print(f"There are some yml properties without valid description: (total {len(variables_without_desc)}) {variables_without_desc}.") + total_list = [] + for file in files_to_check: + check_yml(total_list, file) + if len(total_list) > 0: exit(1) else: print("All yml properties have valid description.") \ No newline at end of file diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 082b6c0536..825b197e1d 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -14,13 +14,12 @@ # limitations under the License. # -# If you enabled process metrics you should also enable 'web-environment'. -spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" -# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. -spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" - -spring.main.allow-circular-references: "true" +# Spring common parameters +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. +# Server common parameters server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -41,18 +40,27 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cache parameters cache: + # caffeine or redis type: "${CACHE_TYPE:redis}" +# Redis configuration parameters redis: - # standalone or cluster or sentinel connection: + # standalone or cluster or sentinel type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -84,26 +92,43 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" # COAP server parameters transport: coap: + # CoAP bind-address bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" + # CoAP bind port bind_port: "${COAP_BIND_PORT:5683}" + # CoaP processing timeout in milliseconds timeout: "${COAP_TIMEOUT:10000}" + # CoaP piggyback response timeout in milliseconds piggyback_timeout: "${COAP_PIGGYBACK_TIMEOUT:500}" + # Default PSM Activity Timer if not specified in device profile psm_activity_timer: "${COAP_PSM_ACTIVITY_TIMER:10000}" + # Default PSM Activity Timer if not specified in device profile paging_transmission_window: "${COAP_PAGING_TRANSMISSION_WINDOW:10000}" dtls: # Enable/disable DTLS 1.2 support @@ -141,10 +166,14 @@ transport: x509: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${TB_COAP_X509_DTLS_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" + # Inactivity timeout of DTLS session. Used to clean cache dtls_session_inactivity_timeout: "${TB_COAP_X509_DTLS_SESSION_INACTIVITY_TIMEOUT:86400000}" + # Interval of periodic eviction of the timed-out DTLS sessions dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if the device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -152,44 +181,74 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" stats: + # Enable/Disable the collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" + # The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values none or gzip compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside @@ -198,75 +257,130 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" aws_sqs: + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue. Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consumed again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consumed again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: - hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" + # Default topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" js: # JS Eval request topic @@ -280,19 +394,26 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# Service common properties service: - type: "${TB_SERVICE_TYPE:tb-transport}" + type: "${TB_SERVICE_TYPE:tb-transport}" # service type # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" @@ -300,14 +421,19 @@ service: usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" +# General management parameters management: endpoints: web: @@ -315,6 +441,7 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 6c5ddb9c52..315b138bfa 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -14,8 +14,7 @@ # limitations under the License. # -spring.main.allow-circular-references: "true" - +# Server common properties server: # Server bind address address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -54,6 +53,9 @@ server: # Enable/disable HTTP/2 support enabled: "${HTTP2_ENABLED:true}" +# Spring common parameters +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. + # Zookeeper connection parameters. Used for service discovery. zk: # Enable/disable zookeeper discovery service. @@ -68,18 +70,28 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cache parameters cache: + # caffeine or redis type: "${CACHE_TYPE:redis}" +# Redis configuration parameters redis: # standalone or cluster or sentinel connection: + # Redis deployment type: Standalone (single Redis node deployment) OR Cluster type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -111,25 +123,40 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" # HTTP server parameters transport: http: + # HTTP request processing timeout in milliseconds request_timeout: "${HTTP_REQUEST_TIMEOUT:60000}" + # HTTP maximum request processing timeout in milliseconds max_request_timeout: "${HTTP_MAX_REQUEST_TIMEOUT:300000}" sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -137,44 +164,73 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" stats: + # Enable/Disable collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for client and can be used for two-way authentication for client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server host name. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside @@ -183,75 +239,131 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" aws_sqs: + # Use default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds + transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue.Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consume again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consume again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consume again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consume again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: - hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" + # Default topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" js: # JS Eval request topic @@ -265,19 +377,26 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# General service parameters service: - type: "${TB_SERVICE_TYPE:tb-transport}" + type: "${TB_SERVICE_TYPE:tb-transport}" # type of service # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" @@ -285,14 +404,19 @@ service: usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" +# General management parameters management: endpoints: web: @@ -300,6 +424,7 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index 4c0a33929a..db4870e40b 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -14,13 +14,12 @@ # limitations under the License. # -# If you enabled process metrics you should also enable 'web-environment'. -spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" -# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. -spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" - -spring.main.allow-circular-references: "true" +# Spring common parameters +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. +# Server common parameters server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -41,18 +40,27 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cache parameters cache: + # caffeine or redis type: "${CACHE_TYPE:redis}" +# Redis configuration parameters redis: - # standalone or cluster or sentinel connection: + # standalone or cluster or sentinel type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -84,22 +92,35 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" # LWM2M server parameters transport: sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if the device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -107,11 +128,14 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" client_side_rpc: + # Processing timeout interval of the RPC command on the CLIENT SIDE. Time in milliseconds 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}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" # Local LwM2M transport parameters lwm2m: @@ -121,11 +145,16 @@ transport: # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 retransmission_timeout: "${LWM2M_DTLS_RETRANSMISSION_TIMEOUT_MS:9000}" server: + # LwM2M Server ID id: "${LWM2M_SERVER_ID:123}" + # LwM2M server bind address. Bind to all interfaces by default bind_address: "${LWM2M_BIND_ADDRESS:0.0.0.0}" + # LwM2M server bind port bind_port: "${LWM2M_BIND_PORT:5685}" security: + # LwM2M server bind address for DTLS. Bind to all interfaces by default bind_address: "${LWM2M_SECURITY_BIND_ADDRESS:0.0.0.0}" + # LwM2M server bind port for DTLS bind_port: "${LWM2M_SECURITY_BIND_PORT:5686}" # Server X509 Certificates support credentials: @@ -156,12 +185,18 @@ transport: # Only Certificate_x509: skip_validity_check_for_client_cert: "${TB_LWM2M_SERVER_SECURITY_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" bootstrap: + # Enable/disable Bootstrap Server enabled: "${LWM2M_ENABLED_BS:true}" + # Default value in Lwm2mClient after start in mode Bootstrap for the object : name "LWM2M Security" field: "Short Server ID" (deviceProfile: Bootstrap.BOOTSTRAP SERVER.Short ID) id: "${LWM2M_SERVER_ID_BS:111}" + # LwM2M bootstrap server bind address. Bind to all interfaces by default bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" + # LwM2M bootstrap server bind port bind_port: "${LWM2M_BS_BIND_PORT:5687}" security: + # LwM2M bootstrap server bind address for DTLS. Bind to all interfaces by default bind_address: "${LWM2M_BS_SECURITY_BIND_ADDRESS:0.0.0.0}" + # LwM2M bootstrap server bind address for DTLS. Bind to all interfaces by default bind_port: "${LWM2M_BS_SECURITY_BIND_PORT:5688}" # Bootstrap server X509 Certificates support credentials: @@ -208,54 +243,91 @@ transport: 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}" + # Set usage of recommended cipher suites; true - allow only recommended cipher suites; false - allow not recommended cipher suites recommended_ciphers: "${LWM2M_RECOMMENDED_CIPHERS:false}" + # Set usage of recommended supported groups (curves); true - allow only recommended supported groups, false - allow not recommended supported groups recommended_supported_groups: "${LWM2M_RECOMMENDED_SUPPORTED_GROUPS:true}" + # Timeout of LwM2M operation timeout: "${LWM2M_TIMEOUT:120000}" + # Thread pool size for processing of the LwM2M uplinks uplink_pool_size: "${LWM2M_UPLINK_POOL_SIZE:10}" + # Thread pool size for processing of the LwM2M downlinks downlink_pool_size: "${LWM2M_DOWNLINK_POOL_SIZE:10}" + # Thread pool size for processing of the OTA updates ota_pool_size: "${LWM2M_OTA_POOL_SIZE:10}" + # Period of cleanup for the registrations in store clean_period_in_sec: "${LWM2M_CLEAN_PERIOD_IN_SEC:2}" + # PSM Activity Timer if not specified in the device profile psm_activity_timer: "${LWM2M_PSM_ACTIVITY_TIMER:10000}" + # Paging Transmission Window for eDRX support if not specified in the device profile paging_transmission_window: "${LWM2M_PAGING_TRANSMISSION_WINDOW:10000}" 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: + # Enable/Disable the collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" +# Queue configuration properties queue: type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" + # The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values none or gzip compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside @@ -264,74 +336,128 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" aws_sqs: + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue. Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consumed again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consumed again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: - hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" js: # JS Eval request topic @@ -347,19 +473,26 @@ queue: # JS response auto commit interval response_auto_commit_interval: "${REMOTE_JS_RESPONSE_AUTO_COMMIT_INTERVAL_MS:100}" rule-engine: + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# Service common parameters service: - type: "${TB_SERVICE_TYPE:tb-transport}" + type: "${TB_SERVICE_TYPE:tb-transport}" # service type # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" @@ -367,14 +500,19 @@ service: usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" +# General management parameters management: endpoints: web: @@ -382,6 +520,7 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 67986e4bfc..ff26bb6e38 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -14,13 +14,12 @@ # limitations under the License. # -# If you enabled process metrics you should also enable 'web-environment'. -spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" -# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. -spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" - -spring.main.allow-circular-references: "true" +# Spring common parameters +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. +# Server common parameters server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -41,18 +40,28 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cache parameters cache: + # caffeine or redis type: "${CACHE_TYPE:redis}" +# Redis configuration parameters redis: # standalone or cluster or sentinel connection: + # Redis deployment type: Standalone (single Redis node deployment) OR Cluster type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -84,39 +93,58 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" # MQTT server parameters transport: mqtt: + # MQTT bind-address bind_address: "${MQTT_BIND_ADDRESS:0.0.0.0}" + # MQTT bind port bind_port: "${MQTT_BIND_PORT:1883}" # Enable proxy protocol support. Disabled by default. If enabled, supports both v1 and v2. # Useful to get the real IP address of the client in the logs and for rate limits. proxy_enabled: "${MQTT_PROXY_PROTOCOL_ENABLED:false}" + # MQTT processing timeout in milliseconds timeout: "${MQTT_TIMEOUT:10000}" msg_queue_size_per_device_limit: "${MQTT_MSG_QUEUE_SIZE_PER_DEVICE_LIMIT:100}" # messages await in the queue before device connected state. This limit works on low level before TenantProfileLimits mechanism netty: + # Netty leak detector level leak_detector_level: "${NETTY_LEAK_DETECTOR_LVL:DISABLED}" + # Netty BOSS threads count boss_group_thread_count: "${NETTY_BOSS_GROUP_THREADS:1}" + # Netty worker threads count worker_group_thread_count: "${NETTY_WORKER_GROUP_THREADS:12}" + # Max payload size in bytes max_payload_size: "${NETTY_MAX_PAYLOAD_SIZE:65536}" + # Enables TCP keepalive. This means that TCP starts sending keepalive probes when a connection is idle for some time so_keep_alive: "${NETTY_SO_KEEPALIVE:false}" # MQTT SSL configuration ssl: # Enable/disable SSL support enabled: "${MQTT_SSL_ENABLED:false}" - # MQTT SSL bind address + # MQTT SSL bind-address bind_address: "${MQTT_SSL_BIND_ADDRESS:0.0.0.0}" # MQTT SSL bind port bind_port: "${MQTT_SSL_BIND_PORT:8883}" @@ -149,7 +177,9 @@ transport: # Skip certificate validity check for client certificates. skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if the device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -157,12 +187,17 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" stats: + # Enable/Disable the collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" client_side_rpc: + # Processing timeout interval of the RPC command on the CLIENT SIDE. Time in milliseconds timeout: "${CLIENT_SIDE_RPC_TIMEOUT:60000}" rate_limits: # Enable or disable generic rate limits. Device and Tenant specific rate limits are controlled in Tenant Profile. @@ -172,39 +207,64 @@ transport: # Timeout to expire block IP addresses ip_block_timeout: "${TB_TRANSPORT_IP_BLOCK_TIMEOUT:60000}" - +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" + # The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values none or gzip compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside @@ -213,75 +273,130 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" aws_sqs: + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue.Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consumed again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consumed again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: - hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" + # Default topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" js: # JS Eval request topic @@ -295,19 +410,26 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# Service common properties service: - type: "${TB_SERVICE_TYPE:tb-transport}" + type: "${TB_SERVICE_TYPE:tb-transport}" # service type # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" @@ -315,14 +437,19 @@ service: usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" +# General management parameters management: endpoints: web: @@ -330,6 +457,7 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index e141f80321..db883dcd30 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -14,13 +14,12 @@ # limitations under the License. # -# If you enabled process metrics you should also enable 'web-environment'. -spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" -# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. -spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" - -spring.main.allow-circular-references: "true" +# Spring common parameters +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. +# Server common parameters server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -41,18 +40,27 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Cache parameters cache: + # caffeine or redis type: "${CACHE_TYPE:redis}" +# Redis configuration parameters redis: - # standalone or cluster or sentinel connection: + # standalone or cluster or sentinel type: "${REDIS_CONNECTION_TYPE:standalone}" standalone: + # Redis connection host host: "${REDIS_HOST:localhost}" + # Redis connection port port: "${REDIS_PORT:6379}" + # Use default Redis configuration file useDefaultClientConfig: "${REDIS_USE_DEFAULT_CLIENT_CONFIG:true}" # this value may be used only if you used not default ClientConfig clientName: "${REDIS_CLIENT_NAME:standalone}" @@ -84,32 +92,50 @@ redis: password: "${REDIS_PASSWORD:}" # pool config pool_config: + # Maximum number of connections that can be allocated by the connection pool maxTotal: "${REDIS_POOL_CONFIG_MAX_TOTAL:128}" + # Maximum number of idle connections that can be maintained in the pool without being closed maxIdle: "${REDIS_POOL_CONFIG_MAX_IDLE:128}" + # Minumum number of idle connections that can be maintained in the pool without being closed minIdle: "${REDIS_POOL_CONFIG_MIN_IDLE:16}" + # Enable/Disable PING command send when a connection is borrowed testOnBorrow: "${REDIS_POOL_CONFIG_TEST_ON_BORROW:true}" + # The property is used to specify whether to test the connection before returning it to the connection pool. testOnReturn: "${REDIS_POOL_CONFIG_TEST_ON_RETURN:true}" + # The property is used in the context of connection pooling in Redis testWhileIdle: "${REDIS_POOL_CONFIG_TEST_WHILE_IDLE:true}" + # Minimum amount of time that an idle connection should be idle before it can be evicted from the connection pool. Value set in milliseconds minEvictableMs: "${REDIS_POOL_CONFIG_MIN_EVICTABLE_MS:60000}" + # Specifies the time interval in milliseconds between two consecutive eviction runs evictionRunsMs: "${REDIS_POOL_CONFIG_EVICTION_RUNS_MS:30000}" + # Maximum time in milliseconds where a client is willing to wait for a connection from the pool when all connections are exhausted maxWaitMills: "${REDIS_POOL_CONFIG_MAX_WAIT_MS:60000}" + # Specifies the number of connections to test for eviction during each eviction run numberTestsPerEvictionRun: "${REDIS_POOL_CONFIG_NUMBER_TESTS_PER_EVICTION_RUN:3}" + # Determines the behavior when a thread requests a connection from the pool but there are no available connections and the pool cannot create more due to the maxTotal configuration blockWhenExhausted: "${REDIS_POOL_CONFIG_BLOCK_WHEN_EXHAUSTED:true}" +# Snmp server parameters transport: snmp: + # Enable/disable SNMP transport protocol enabled: "${SNMP_ENABLED:true}" + # Snmp bind port bind_port: "${SNMP_BIND_PORT:1620}" response_processing: # parallelism level for executor (workStealingPool) that is responsible for handling responses from SNMP devices parallelism_level: "${SNMP_RESPONSE_PROCESSING_PARALLELISM_LEVEL:20}" # to configure SNMP to work over UDP or TCP underlying_protocol: "${SNMP_UNDERLYING_PROTOCOL:udp}" + # Batch size to request OID mappings from the device (useful when the device profile has multiple hundreds of OID mappings) max_request_oids: "${SNMP_MAX_REQUEST_OIDS:100}" response: + # To ignore SNMP response values that do not match the data type of the configured OID mapping (by default false - will throw an error if any value of the response not match configured data types) ignore_type_cast_errors: "${SNMP_RESPONSE_IGNORE_TYPE_CAST_ERRORS:false}" sessions: + # Inactivity timeout for device session in transport service. The last activity time of the device session is updated if the device sends any message, including keepalive messages inactivity_timeout: "${TB_TRANSPORT_SESSIONS_INACTIVITY_TIMEOUT:300000}" + # Interval of periodic check for expired sessions and report of the changes to session last activity time report_timeout: "${TB_TRANSPORT_SESSIONS_REPORT_TIMEOUT:3000}" json: # Cast String data types to Numeric if possible when processing Telemetry/Attributes JSON @@ -117,44 +143,74 @@ transport: # Maximum allowed string value length when processing Telemetry/Attributes JSON (0 value disables string value length check) max_string_value_length: "${JSON_MAX_STRING_VALUE_LENGTH:0}" log: + # Enable/Disable log of transport messages to telemetry. For example, logging of LwM2M registration update enabled: "${TB_TRANSPORT_LOG_ENABLED:true}" + # Maximum length of the log message. The content will be truncated to the specified value if needed max_length: "${TB_TRANSPORT_LOG_MAX_LENGTH:1024}" stats: + # Enable/Disable collection of transport statistics enabled: "${TB_TRANSPORT_STATS_ENABLED:true}" + # Interval of transport statistics logging print-interval-ms: "${TB_TRANSPORT_STATS_PRINT_INTERVAL_MS:60000}" +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:kafka}" # kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" + # The compression type for all data generated by the producer. The default is none (i.e. no compression). Valid values none or gzip compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" other-inline: "${TB_QUEUE_KAFKA_OTHER_PROPERTIES:}" # In this section you can specify custom parameters (semicolon separated) for Kafka consumer/producer/admin # Example "metrics.recording.level:INFO;metrics.sample.window.ms:30000" other: # DEPRECATED. In this section you can specify custom parameters for Kafka consumer/producer and expose the env variables to configure outside @@ -163,79 +219,137 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Rule Engine rule-engine: "${TB_QUEUE_KAFKA_RE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Transport Api topics transport-api: "${TB_QUEUE_KAFKA_TA_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:10;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" consumer-stats: + # Prints lag between consumer group offset and last messages offset in Kafka topics enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" + # Statistics printing interval for Kafka's consumer-groups stats print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" + # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" aws_sqs: + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds rule-engine: "${TB_QUEUE_AWS_SQS_RE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds transport-api: "${TB_QUEUE_AWS_SQS_TA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" - max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Message size for PubSub queue. Value in bytes + max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Rule Engine subscribers, messages which will commit after ackDeadlineInSec period can be consumed again rule-engine: "${TB_QUEUE_PUBSUB_RE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport API subscribers, messages which will commit after ackDeadlineInSec period can be consumed again transport-api: "${TB_QUEUE_PUBSUB_TA_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Rule Engine queues rule-engine: "${TB_QUEUE_SERVICE_BUS_RE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Transport Api queues transport-api: "${TB_QUEUE_SERVICE_BUS_TA_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Rule Engine queues rule-engine: "${TB_QUEUE_RABBIT_MQ_RE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Notification queues notifications: "${TB_QUEUE_RABBIT_MQ_NOTIFICATIONS_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: - hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" + hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 transport_api: + # Topic used to consume api requests from transport microservices requests_topic: "${TB_QUEUE_TRANSPORT_API_REQUEST_TOPIC:tb_transport.api.requests}" + # Topic used to produce api responses to transport microservices responses_topic: "${TB_QUEUE_TRANSPORT_API_RESPONSE_TOPIC:tb_transport.api.responses}" + # Maximum pending api requests from transport microservices to be handled by server max_pending_requests: "${TB_QUEUE_TRANSPORT_MAX_PENDING_REQUESTS:10000}" + # Maximum timeout in milliseconds to handle api request from transport microservice by server max_requests_timeout: "${TB_QUEUE_TRANSPORT_MAX_REQUEST_TIMEOUT:10000}" + # Amount of threads used to invoke callbacks max_callback_threads: "${TB_QUEUE_TRANSPORT_MAX_CALLBACK_THREADS:100}" + # Interval in milliseconds to poll api requests from transport microservices request_poll_interval: "${TB_QUEUE_TRANSPORT_REQUEST_POLL_INTERVAL_MS:25}" + # Interval in milliseconds to poll api response from transport microservices response_poll_interval: "${TB_QUEUE_TRANSPORT_RESPONSE_POLL_INTERVAL_MS:25}" core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:60000}" + # Stats topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:false}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:10000}" js: # JS Eval request topic @@ -249,19 +363,26 @@ queue: # JS response poll interval response_poll_interval: "${REMOTE_JS_RESPONSE_POLL_INTERVAL_MS:25}" rule-engine: + # Deprecated. It will be removed in the nearest releases topic: "${TB_QUEUE_RULE_ENGINE_TOPIC:tb_rule_engine}" + # Interval in milliseconds to poll messages by Rule Engine poll-interval: "${TB_QUEUE_RULE_ENGINE_POLL_INTERVAL_MS:25}" + # Timeout for processing a message pack of Rule Engine pack-processing-timeout: "${TB_QUEUE_RULE_ENGINE_PACK_PROCESSING_TIMEOUT_MS:60000}" stats: + # Enable/disable statistics for Rule Engine enabled: "${TB_QUEUE_RULE_ENGINE_STATS_ENABLED:true}" + # Statistics printing interval for Rule Engine print-interval-ms: "${TB_QUEUE_RULE_ENGINE_STATS_PRINT_INTERVAL_MS:60000}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" + # Interval in milliseconds to poll messages poll_interval: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_POLL_INTERVAL_MS:25}" +# Service common parameters service: - type: "${TB_SERVICE_TYPE:tb-transport}" + type: "${TB_SERVICE_TYPE:tb-transport}" # service type # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" @@ -269,14 +390,19 @@ service: usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" +# General management parameters management: endpoints: web: @@ -284,6 +410,7 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' From dd0cd79fa4a98a61fc652f1bb2d46f3d12d50c2b Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 11 Oct 2023 18:56:24 +0300 Subject: [PATCH 159/267] UI: improved usability of alarm additional info --- .../components/profile/alarm/alarm-rule.component.html | 2 +- .../alarm/edit-alarm-details-dialog.component.html | 8 ++++---- ui-ngx/src/assets/locale/locale.constant-ca_ES.json | 8 ++++---- ui-ngx/src/assets/locale/locale.constant-cs_CZ.json | 6 +++--- ui-ngx/src/assets/locale/locale.constant-da_DK.json | 6 +++--- ui-ngx/src/assets/locale/locale.constant-en_US.json | 8 ++++---- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 7 ++++--- ui-ngx/src/assets/locale/locale.constant-ko_KR.json | 6 +++--- ui-ngx/src/assets/locale/locale.constant-sl_SI.json | 6 +++--- ui-ngx/src/assets/locale/locale.constant-tr_TR.json | 6 +++--- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 8 ++++---- ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 8 ++++---- 12 files changed, 40 insertions(+), 39 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html index 5e7ca9b096..134651a1fd 100644 --- a/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html +++ b/ui-ngx/src/app/modules/home/components/profile/alarm/alarm-rule.component.html @@ -22,7 +22,7 @@
- {{ alarmRuleFormGroup.get('alarmDetails').value ? ('device-profile.alarm-rule-details' | translate) + ': ' : ('device-profile.add-alarm-rule-details' | translate) }} + {{ ('device-profile.alarm-rule-additional-info' | translate) + ': ' }} -

{{ 'device-profile.alarm-rule-details' | translate }}

+

{{ 'device-profile.edit-alarm-rule-additional-info' | translate }}

diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 0b7b09d15b..71d2d45224 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -1507,9 +1507,10 @@ "condition-duration-value-required": "Cal valor de duració.", "condition-duration-time-unit-required": "Cal una unidad del temps.", "advanced-settings": "Configuració avançada", - "alarm-rule-details": "Detalls", - "alarm-rule-details-hint": "Suggeriment: utilitzeu ${keyName} per substituir els valors de les claus d'atribut o de telemetria que s'utilitzen en condicions de regla d'alarma.", - "add-alarm-rule-details": "Afegir detalls", + "alarm-rule-additional-info": "Información adicional", + "edit-alarm-rule-additional-info": "Editar información adicional", + "alarm-rule-additional-info-placeholder": "Proporcione sus comentarios y ajustes aquí para mostrarlos en Detalles de alarma en Información adicional", + "alarm-rule-additional-info-hint": "Suggeriment: utilitzeu ${keyName} per substituir els valors de les claus d'atribut o de telemetria que s'utilitzen en condicions de regla d'alarma.", "alarm-rule-mobile-dashboard": "Tauler de control mòbil", "alarm-rule-mobile-dashboard-hint": "Utilitzat per l'aplicació mòbil com a quadre de comandament de detalls d'alarma", "alarm-rule-no-mobile-dashboard": "No s'ha seleccionat cap tauler", @@ -1519,7 +1520,6 @@ "propagate-alarm-to-owner": "Propaga l'alarma al propietari de l'entitat (Customer or Tenant)", "propagate-alarm-to-owner-hierarchy": "Propaga l'alarma a la jerarquia dels propietaris de l'entitat", "propagate-alarm-to-tenant": "Propaga l'alarma al llogater", - "alarm-details": "Detalls d'alarma", "alarm-rule-condition": "Condicions de regla d'alarma", "enter-alarm-rule-condition-prompt": "Per favor, afegir una condició d'alarma", "edit-alarm-rule-condition": "Editar condició d'alarma", 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 c82ba68649..50b105381f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1143,15 +1143,15 @@ "condition-duration-value-required": "Doba trvání je povinná.", "condition-duration-time-unit-required": "Jednotka času je povinná.", "advanced-settings": "Pokročilá nastavení", - "alarm-rule-details": "Detail", - "add-alarm-rule-details": "Přidat detail", + "alarm-rule-additional-info": "Doplňující informace", + "edit-alarm-rule-additional-info": "Upravit další informace", + "alarm-rule-additional-info-placeholder": "Zde uveďte své komentáře a úpravy, aby se zobrazily v detailech alarmu v části Další informace", "alarm-rule-mobile-dashboard": "Mobilní dashboard", "alarm-rule-mobile-dashboard-hint": "Používán mobilní aplikací jako dashboard detailu alarmu", "alarm-rule-no-mobile-dashboard": "Žádný dashboard nebyl vybrán", "propagate-alarm": "Propagovat alarm", "alarm-rule-relation-types-list": "Typy vztahů ke zpropagování", "alarm-rule-relation-types-list-hint": "Pokud nejsou vybrány žádné typy vztahů, alarmy budou propagovány bez filtru typu vztahu.", - "alarm-details": "Detail alarmu", "alarm-rule-condition": "Podmínka pravidla alarmu", "enter-alarm-rule-condition-prompt": "Přidejte prosím podmínku pravidla alarmu", "edit-alarm-rule-condition": "Editovat podmínku pravidla alarmu", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 834cc15619..3fdaa613e9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -1197,12 +1197,12 @@ "condition-duration-value-required": "Varighedsværdi er påkrævet.", "condition-duration-time-unit-required": "Tidsenhed er påkrævet.", "advanced-settings": "Avancerede indstillinger", - "alarm-rule-details": "Oplysninger", - "add-alarm-rule-details": "Tilføj oplysninger", + "alarm-rule-additional-info": "Yderligere information", + "edit-alarm-rule-additional-info": "Rediger yderligere oplysninger", + "alarm-rule-additional-info-placeholder": "Angiv venligst dine kommentarer og justeringer her for at vise dem i Alarmdetaljer under Yderligere info", "propagate-alarm": "Overfør alarm", "alarm-rule-relation-types-list": "Relationstyper, der skal overføres", "alarm-rule-relation-types-list-hint": "Hvis der ikke vælges Overfør relationstyper vil alarmer blive overført uden filtrering på relationstype.", - "alarm-details": "Alarmoplysninger", "alarm-rule-condition": "Alarmregelbetingelse", "enter-alarm-rule-condition-prompt": "Tilføj alarmregelbetingelse", "edit-alarm-rule-condition": "Rediger alarmregelbetingelse", 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 0fdf48d12c..79c6deb28b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1622,9 +1622,10 @@ "condition-duration-value-required": "Duration value is required.", "condition-duration-time-unit-required": "Time unit is required.", "advanced-settings": "Advanced settings", - "alarm-rule-details": "Details", - "alarm-rule-details-hint": "Hint: use ${keyName} to substitute values of the attribute or telemetry keys that are used in alarm rule condition.", - "add-alarm-rule-details": "Add details", + "alarm-rule-additional-info": "Additional info", + "edit-alarm-rule-additional-info": "Edit additional info", + "alarm-rule-additional-info-placeholder": "Please provide your comments and adjustments here to display them within Alarm details under Additional info", + "alarm-rule-additional-info-hint": "Hint: use ${keyName} to substitute values of the attribute or telemetry keys that are used in alarm rule condition.", "alarm-rule-mobile-dashboard": "Mobile dashboard", "alarm-rule-mobile-dashboard-hint": "Used by mobile application as an alarm details dashboard", "alarm-rule-no-mobile-dashboard": "No dashboard selected", @@ -1633,7 +1634,6 @@ "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", "propagate-alarm-to-owner": "Propagate alarm to entity owner (Customer or Tenant)", "propagate-alarm-to-tenant": "Propagate alarm to Tenant", - "alarm-details": "Alarm details", "alarm-rule-condition": "Alarm rule condition", "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", "edit-alarm-rule-condition": "Edit alarm rule condition", 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 143bed648b..7ebb27d63a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1509,9 +1509,11 @@ "condition-duration-value-required": "Se requiere valor de duración.", "condition-duration-time-unit-required": "Se requiere una unidad de tiempo.", "advanced-settings": "Ajustes avanzados", - "alarm-rule-details": "Detalles", + "alarm-rule-additional-info": "Informació addicional", + "edit-alarm-rule-additional-info": "Editeu informació addicional", + "alarm-rule-additional-info-placeholder": "Si us plau, proporcioneu els vostres comentaris i ajustos aquí per mostrar-los a Detalls d'alarma a Informació addicional", "alarm-rule-details-hint": "Ayuda: usa ${nombredeClave} para sustituir los valores de atributos o telemetrías usadas en la condición de la regla de alarma.", - "add-alarm-rule-details": "Añadir detalles", + "add-alarm-rule-additional-info": "Añadir detalles", "alarm-rule-mobile-dashboard": "Panel Móvil", "alarm-rule-mobile-dashboard-hint": "Usado por la aplicación móvil como panel de detalle de alarmas", "alarm-rule-no-mobile-dashboard": "No hay panel seleccionado", @@ -1520,7 +1522,6 @@ "alarm-rule-relation-types-list-hint": "Si no está seleccionado 'propagar relaciones', las alarmas serán propagadas sin filtrar por relación.", "propagate-alarm-to-owner": "Propagar alarma al propietario de la entidad (Cliente o Administrador)", "propagate-alarm-to-tenant": "Propagar alarma a Administrador", - "alarm-details": "Detalles de alarma", "alarm-rule-condition": "Condiciones de regla de alarma", "enter-alarm-rule-condition-prompt": "Por favor, añade una condición de alarma", "edit-alarm-rule-condition": "Editar condición de alarma", 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 aad25e9c0e..8a46e39466 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -1010,12 +1010,12 @@ "condition-duration-value-required": "Duration value is required.", "condition-duration-time-unit-required": "Time unit is required.", "advanced-settings": "Advanced settings", - "alarm-rule-details": "Details", - "add-alarm-rule-details": "Add details", + "alarm-rule-additional-info": "추가 정보", + "edit-alarm-rule-additional-info": "추가 정보 수정", + "alarm-rule-additional-info-placeholder": "추가 정보 아래의 경보 세부정보에 표시하려면 여기에 의견과 조정 사항을 입력하세요.", "propagate-alarm": "Propagate alarm", "alarm-rule-relation-types-list": "Relation types to propagate", "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", - "alarm-details": "Alarm details", "alarm-rule-condition": "Alarm rule condition", "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", "edit-alarm-rule-condition": "Edit alarm rule condition", 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 c6a20b9a36..d1ea6a188e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -1010,12 +1010,12 @@ "condition-duration-value-required": "Duration value is required.", "condition-duration-time-unit-required": "Time unit is required.", "advanced-settings": "Advanced settings", - "alarm-rule-details": "Details", - "add-alarm-rule-details": "Add details", + "alarm-rule-additional-info": "Dodatne informacije", + "edit-alarm-rule-additional-info": "Uredi dodatne informacije", + "alarm-rule-additional-info-placeholder": "Tukaj navedite svoje komentarje in prilagoditve, da jih prikažete v podrobnostih alarma pod dodatnimi informacijami", "propagate-alarm": "Propagate alarm", "alarm-rule-relation-types-list": "Relation types to propagate", "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", - "alarm-details": "Alarm details", "alarm-rule-condition": "Alarm rule condition", "enter-alarm-rule-condition-prompt": "Please add alarm rule condition", "edit-alarm-rule-condition": "Edit alarm rule condition", 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 b377c9fd45..4c62b2ffa6 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1146,15 +1146,15 @@ "condition-duration-value-required": "Süre değeri gerekli.", "condition-duration-time-unit-required": "Zaman birimi gerekli.", "advanced-settings": "Gelişmiş ayarlar", - "alarm-rule-details": "Detaylar", - "add-alarm-rule-details": "Detay ekle", + "alarm-rule-additional-info": "Ilave bilgi", + "edit-alarm-rule-additional-info": "Ek bilgileri düzenle", + "alarm-rule-additional-info-placeholder": "Lütfen yorumlarınızı ve ayarlamalarınızı Ek bilgiler altındaki Alarm ayrıntılarında görüntülemek için buraya girin.", "alarm-rule-mobile-dashboard": "Mobil gösterge paneli", "alarm-rule-mobile-dashboard-hint": "Mobil uygulama tarafından alarm ayrıntıları gösterge paneli olarak kullanılır", "alarm-rule-no-mobile-dashboard": "Gösterge paneli seçilmedi", "propagate-alarm": "Alarmı yay", "alarm-rule-relation-types-list": "Yayılacak ilişki türleri", "alarm-rule-relation-types-list-hint": "Yayma ilişki türleri seçilmezse, alarmlar ilişki türüne göre filtreleme yapılmadan yayılır.", - "alarm-details": "Alarm ayrıntıları", "alarm-rule-condition": "Alarm kuralı koşulu", "enter-alarm-rule-condition-prompt": "Lütfen alarm kuralı koşulu ekleyin", "edit-alarm-rule-condition": "Alarm kuralı koşulunu düzenle", 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 895499e067..0554f90d5b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1511,9 +1511,10 @@ "condition-duration-value-required": "持续时间值必填。", "condition-duration-time-unit-required": "时间单位必填。", "advanced-settings": "高级设置", - "alarm-rule-details": "详情", - "alarm-rule-details-hint": "提示: 使用 ${keyName} 来替代告警规则条件中使用的属性或遥测键的值。", - "add-alarm-rule-details": "详情模板:", + "alarm-rule-additional-info": "附加信息", + "edit-alarm-rule-additional-info": "编辑附加信息", + "alarm-rule-additional-info-placeholder": "请在此处提供您的意见和调整,以便将其显示在“附加信息”下的“警报详细信息”中", + "alarm-rule-additional-info-hint": "提示: 使用 ${keyName} 来替代告警规则条件中使用的属性或遥测键的值。", "alarm-rule-mobile-dashboard": "移动端仪表板", "alarm-rule-mobile-dashboard-hint": "作为移动端告警详情仪表板使用。", "alarm-rule-no-mobile-dashboard": "未选择仪表板。", @@ -1522,7 +1523,6 @@ "alarm-rule-relation-types-list-hint": "如果未选择传递关联类型,则将不按关联类型过滤而传递告警。", "propagate-alarm-to-owner": "将告警传播给实体所有者(客户或租户)。", "propagate-alarm-to-tenant": "将告警传播给租户", - "alarm-details": "告警详细信息", "alarm-rule-condition": "告警规则条件", "enter-alarm-rule-condition-prompt": "请添加告警规则条件", "edit-alarm-rule-condition": "编辑告警规则条件", 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 bb655f65e7..d5b28afc32 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1308,9 +1308,10 @@ "condition-duration-value-required": "需要持續時間值。", "condition-duration-time-unit-required": "需要時間單位。", "advanced-settings": "進階設定", - "alarm-rule-details": "詳細資訊", - "alarm-rule-details-hint": "提示:使用${keyName}替換警告規則條件中使用的屬性或遙測鍵的值。", - "add-alarm-rule-details": "增加詳細資訊", + "alarm-rule-additional-info": "附加資訊", + "edit-alarm-rule-additional-info": "編輯附加資訊", + "alarm-rule-additional-info-placeholder": "請在此處提供您的評論和調整,以便在附加資訊下的警報詳細資訊中顯示它們。", + "alarm-rule-additional-info-hint": "提示:使用${keyName}替換警告規則條件中使用的屬性或遙測鍵的值。", "alarm-rule-mobile-dashboard": "移動儀表板", "alarm-rule-mobile-dashboard-hint": "由移動應用程序用作警告詳情儀表板", "alarm-rule-no-mobile-dashboard": "未選擇儀表板", @@ -1319,7 +1320,6 @@ "alarm-rule-relation-types-list-hint": "如果未選擇傳播關聯類型,則將在不按關聯類型過濾的情況下傳播警告。", "propagate-alarm-to-owner": "傳播警告給相關實體擁有者", "propagate-alarm-to-tenant": "傳播警告給租戶", - "alarm-details": "警告詳細資料", "alarm-rule-condition": "警告規則條件", "enter-alarm-rule-condition-prompt": "請新增警告規則條件", "edit-alarm-rule-condition": "編輯警告規則條件", From 902e153683294677b3afdefd3dffdf59a6a065d9 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 12 Oct 2023 13:24:14 +0300 Subject: [PATCH 160/267] renamed mqtts ca file for device connectivity --- .../DeviceConnectivityController.java | 6 ++-- .../src/main/resources/thingsboard.yml | 2 +- .../DeviceConnectivityControllerTest.java | 32 +++++++++---------- ...ectivityControllerWithDefaultPortTest.java | 21 ------------ .../dao/util/DeviceConnectivityUtil.java | 6 ++-- 5 files changed, 23 insertions(+), 44 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index 23985f3975..dfd8109e75 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -50,7 +50,7 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PA import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FILE_NAME; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_FILE_PEM; @RestController @TbCoreComponent @@ -129,8 +129,8 @@ public class DeviceConnectivityController extends BaseController { checkNotNull(deviceConnectivityService.getPemCertFile(protocol), protocol + " pem cert file is not found!"); return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + PEM_CERT_FILE_NAME) - .header("x-filename", PEM_CERT_FILE_NAME) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + CA_FILE_PEM) + .header("x-filename", CA_FILE_PEM) .contentLength(pemCert.contentLength()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(pemCert); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index b73c4f1fda..a4ab774b2c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1180,7 +1180,7 @@ device: # Port of mqtt transport service. If empty default port for mqtts will be used. port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" # Path to the server certificate file - pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:mqttserver.pem}" + pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:cafile.pem}" coap: # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 237f900d47..1a68d80753 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -62,14 +62,14 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FILE_NAME; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_FILE_PEM; @TestPropertySource(properties = { "device.connectivity.https.enabled=true", "device.connectivity.http.port=8080", "device.connectivity.https.port=444", "device.connectivity.mqtts.enabled=true", - "device.connectivity.mqtts.pem_cert_file=/tmp/" + PEM_CERT_FILE_NAME, + "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_FILE_PEM, "device.connectivity.coaps.enabled=true", }) @ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class}) @@ -202,8 +202,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -211,8 +211,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", credentials.getCredentialsId())); JsonNode linuxCoapCommands = commands.get(COAP); @@ -240,8 +240,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -249,8 +249,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); } @@ -284,8 +284,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -293,8 +293,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o tb-server-chain.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile tb-server-chain.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); } @@ -368,7 +368,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { @Test @DirtiesContext public void testDownloadMqttCert() throws Exception { - Path path = Files.createFile(Path.of("/tmp/" + PEM_CERT_FILE_NAME)); + Path path = Files.createFile(Path.of("/tmp/" + CA_FILE_PEM)); Files.writeString(path, CERT); try { @@ -382,7 +382,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { @Test @DirtiesContext public void testDownloadMqttCertFromFileWithPrivateKey() throws Exception { - Path path = Files.createFile(Path.of("/tmp/" + PEM_CERT_FILE_NAME)); + Path path = Files.createFile(Path.of("/tmp/" + CA_FILE_PEM)); Files.writeString(path, CERT + P_KEY); try { diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java index 8ca0d07540..bba834912f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerWithDefaultPortTest.java @@ -27,42 +27,21 @@ import org.mockito.AdditionalAnswers; import org.mockito.Mockito; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; -import org.springframework.test.annotation.DirtiesContext; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Device; -import org.thingsboard.server.common.data.DeviceProfile; -import org.thingsboard.server.common.data.DeviceProfileType; -import org.thingsboard.server.common.data.DeviceTransportType; 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.CoapDeviceProfileTransportConfiguration; -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.MqttDeviceProfileTransportConfiguration; -import org.thingsboard.server.common.data.id.DeviceProfileId; 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.device.DeviceDao; import org.thingsboard.server.dao.service.DaoSqlTest; -import java.nio.file.Files; -import java.nio.file.Path; - import static org.assertj.core.api.Assertions.assertThat; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAP; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.COAPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.DOCKER; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.PEM_CERT_FILE_NAME; @TestPropertySource(properties = { "device.connectivity.https.enabled=true", diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index 2bd4882d7e..a38d2bc2d8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -31,7 +31,7 @@ public class DeviceConnectivityUtil { public static final String MQTTS = "mqtts"; public static final String COAP = "coap"; public static final String COAPS = "coaps"; - public static final String PEM_CERT_FILE_NAME = "tb-server-chain.pem"; + public static final String CA_FILE_PEM = "cafile.pem"; public static final String CHECK_DOCUMENTATION = "Check documentation"; public static final String JSON_EXAMPLE_PAYLOAD = "\"{temperature:25}\""; public static final String DOCKER_RUN = "docker run --rm -it "; @@ -47,7 +47,7 @@ public class DeviceConnectivityUtil { public static String getMqttPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { StringBuilder command = new StringBuilder("mosquitto_pub -d -q 1"); if (MQTTS.equals(protocol)) { - command.append(" --cafile ").append(PEM_CERT_FILE_NAME); + command.append(" --cafile ").append(CA_FILE_PEM); } command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); command.append(" -t ").append(deviceTelemetryTopic); @@ -151,7 +151,7 @@ public class DeviceConnectivityUtil { } public static String getCurlPemCertCommand(String baseUrl, String protocol) { - return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", PEM_CERT_FILE_NAME, baseUrl, protocol); + return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", CA_FILE_PEM, baseUrl, protocol); } public static String getCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { From c57ec93e6ab3dc02ca3311634e44105f124ac8fa Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 12 Oct 2023 13:36:22 +0300 Subject: [PATCH 161/267] updated description --- 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 a4ab774b2c..9de4ea32f2 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1179,7 +1179,7 @@ device: host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" # Port of mqtt transport service. If empty default port for mqtts will be used. port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" - # Path to the server certificate file + # Path to the mqtt certificate authority file pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:cafile.pem}" coap: # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. From b35d5364e527958597922793982c8170a8f0fd6a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 12 Oct 2023 16:42:39 +0300 Subject: [PATCH 162/267] added description to tb-vc-executor.yml --- .../src/main/resources/tb-vc-executor.yml | 109 ++++++++++++++++-- tools/src/main/python/check_yml_file.py | 3 +- 2 files changed, 104 insertions(+), 8 deletions(-) diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index ea18768cf3..2a35ee73fd 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -14,13 +14,12 @@ # limitations under the License. # -# If you enabled process metrics you should also enable 'web-environment'. -spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" -# If you enabled process metrics you should set 'web-application-type' to 'servlet' value. -spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" - -spring.main.allow-circular-references: "true" +# Spring common parameters +spring.main.web-environment: "${WEB_APPLICATION_ENABLE:false}" # If you enabled process metrics you should also enable 'web-environment'. +spring.main.web-application-type: "${WEB_APPLICATION_TYPE:none}" # If you enabled process metrics you should set 'web-application-type' to 'servlet' value. +spring.main.allow-circular-references: "true" # Spring Boot configuration property that controls whether circular dependencies between beans are allowed. +# Server common parameters server: # Server bind address (has no effect if web-environment is disabled). address: "${HTTP_BIND_ADDRESS:0.0.0.0}" @@ -41,8 +40,12 @@ zk: session_timeout_ms: "${ZOOKEEPER_SESSION_TIMEOUT_MS:3000}" # Name of the directory in zookeeper 'filesystem' zk_dir: "${ZOOKEEPER_NODES_DIR:/thingsboard}" + # The recalculate_delay property is recommended in a microservices architecture setup for rule-engine services. + # This property provides a pause to ensure that when a rule-engine service is restarted, other nodes don't immediately attempt to recalculate their partitions. + # The delay is recommended because the initialization of rule chain actors is time-consuming. Avoiding unnecessary recalculations during a restart can enhance system performance and stability. recalculate_delay: "${ZOOKEEPER_RECALCULATE_DELAY_MS:0}" +# Queue configuration parameters queue: type: "${TB_QUEUE_TYPE:kafka}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) in_memory: @@ -50,44 +53,72 @@ queue: # For debug lvl print-interval-ms: "${TB_QUEUE_IN_MEMORY_STATS_PRINT_INTERVAL_MS:60000}" kafka: + # Kafka Bootstrap Servers bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: + # Enable/Disable SSL Kafka communication enabled: "${TB_KAFKA_SSL_ENABLED:false}" + # The location of the trust store file truststore.location: "${TB_KAFKA_SSL_TRUSTSTORE_LOCATION:}" + # The password of trust store file if specified truststore.password: "${TB_KAFKA_SSL_TRUSTSTORE_PASSWORD:}" + # The location of the key store file. This is optional for the client and can be used for two-way authentication for the client keystore.location: "${TB_KAFKA_SSL_KEYSTORE_LOCATION:}" + # The store password for the key store file. This is optional for the client and only needed if ‘ssl.keystore.location’ is configured. Key store password is not supported for PEM format keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" + # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all acks: "${TB_KAFKA_ACKS:all}" + # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" compression.type: "${TB_KAFKA_COMPRESSION_TYPE:none}" # none or gzip + # Default batch size. This setting gives the upper bound of the batch size to be sent batch.size: "${TB_KAFKA_BATCH_SIZE:16384}" + # This variable creates a small amount of artificial delay—that is, rather than immediately sending out a record linger.ms: "${TB_KAFKA_LINGER_MS:1}" + # The maximum size of a request in bytes. This setting will limit the number of record batches the producer will send in a single request to avoid sending huge requests max.request.size: "${TB_KAFKA_MAX_REQUEST_SIZE:1048576}" + # The maximum number of unacknowledged requests the client will send on a single connection before blocking max.in.flight.requests.per.connection: "${TB_KAFKA_MAX_IN_FLIGHT_REQUESTS_PER_CONNECTION:5}" + # The total bytes of memory the producer can use to buffer records waiting to be sent to the server buffer.memory: "${TB_BUFFER_MEMORY:33554432}" + # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" + # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" + # The maximum number of records returned in a single call to poll() max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" + # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" + # The maximum amount of data the server will return. Records are fetched in batches by the consumer fetch_max_bytes: "${TB_QUEUE_KAFKA_FETCH_MAX_BYTES:134217728}" request.timeout.ms: "${TB_QUEUE_KAFKA_REQUEST_TIMEOUT_MS:30000}" # (30 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/producer-configs.html#producerconfigs_request.timeout.ms session.timeout.ms: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms auto_offset_reset: "${TB_QUEUE_KAFKA_AUTO_OFFSET_RESET:earliest}" # earliest, latest or none + # Enable/Disable using of Confluent Cloud use_confluent_cloud: "${TB_QUEUE_KAFKA_USE_CONFLUENT_CLOUD:false}" confluent: + # The endpoint identification algorithm used by clients to validate server hostname. The default value is https ssl.algorithm: "${TB_QUEUE_KAFKA_CONFLUENT_SSL_ALGORITHM:https}" + # The mechanism used to authenticate Schema Registry requests. SASL/PLAIN should only be used with TLS/SSL as a transport layer to ensure that clear passwords are not transmitted on the wire without encryption sasl.mechanism: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_MECHANISM:PLAIN}" + # Using JAAS Configuration for specifying multiple SASL mechanisms on a broker sasl.config: "${TB_QUEUE_KAFKA_CONFLUENT_SASL_JAAS_CONFIG:org.apache.kafka.common.security.plain.PlainLoginModule required username=\"CLUSTER_API_KEY\" password=\"CLUSTER_API_SECRET\";}" + # Protocol used to communicate with brokers. Valid values are: PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL security.protocol: "${TB_QUEUE_KAFKA_CONFLUENT_SECURITY_PROTOCOL:SASL_SSL}" # Key-value properties for Kafka consumer per specific topic, e.g. tb_ota_package is a topic name for ota, tb_rule_engine.sq is a topic name for default SequentialByOriginator queue. # Check TB_QUEUE_CORE_OTA_TOPIC and TB_QUEUE_RE_SQ_TOPIC params consumer-properties-per-topic: tb_ota_package: + # Key-value properties for Kafka consumer per specific topic, e.g. tb_ota_package is a topic name for ota, tb_rule_engine.sq is a topic name for default SequentialByOriginator queue. Check TB_QUEUE_CORE_OTA_TOPIC and TB_QUEUE_RE_SQ_TOPIC params - key: max.poll.records + # Example of specific consumer properties value per topic value: "${TB_QUEUE_KAFKA_OTA_MAX_POLL_RECORDS:10}" tb_version_control: + # Example of specific consumer properties value per topic for VC - key: max.poll.interval.ms + # Example of specific consumer properties value per topic for VC value: "${TB_QUEUE_KAFKA_VC_MAX_POLL_INTERVAL_MS:600000}" # tb_rule_engine.sq: # - key: max.poll.records @@ -99,94 +130,155 @@ queue: # - key: "session.timeout.ms" # refer to https://docs.confluent.io/platform/current/installation/configuration/consumer-configs.html#consumerconfigs_session.timeout.ms # value: "${TB_QUEUE_KAFKA_SESSION_TIMEOUT_MS:10000}" # (10 seconds) topic-properties: + # Kafka properties for Core topics core: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Notifications topics notifications: "${TB_QUEUE_KAFKA_NOTIFICATIONS_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" + # Kafka properties for Core topics version-control: "${TB_QUEUE_KAFKA_CORE_TOPIC_PROPERTIES:retention.ms:604800000;segment.bytes:26214400;retention.bytes:1048576000;partitions:1;min.insync.replicas:1}" consumer-stats: + # Prints lag between consumer group offset and last messages offset in Kafka topics enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" + # Statistics printing interval for Kafka's consumer-groups stats print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" + # Time to wait for the stats-loading requests to Kafka to finis kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" aws_sqs: + # Use the default credentials provider for AWS SQS use_default_credential_provider_chain: "${TB_QUEUE_AWS_SQS_USE_DEFAULT_CREDENTIAL_PROVIDER_CHAIN:false}" + # Access key ID from AWS IAM user access_key_id: "${TB_QUEUE_AWS_SQS_ACCESS_KEY_ID:YOUR_KEY}" + # Secret access key from AWS IAM user secret_access_key: "${TB_QUEUE_AWS_SQS_SECRET_ACCESS_KEY:YOUR_SECRET}" + # Region from AWS account region: "${TB_QUEUE_AWS_SQS_REGION:YOUR_REGION}" + # Number of threads per each AWS SQS queue in consumer threads_per_topic: "${TB_QUEUE_AWS_SQS_THREADS_PER_TOPIC:1}" queue-properties: + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds core: "${TB_QUEUE_AWS_SQS_CORE_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # AWS SQS queue properties. VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds notifications: "${TB_QUEUE_AWS_SQS_NOTIFICATIONS_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" + # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds version-control: "${TB_QUEUE_AWS_SQS_VC_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: + # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" + # API Credentials in JSON format service_account: "${TB_QUEUE_PUBSUB_SERVICE_ACCOUNT:YOUR_SERVICE_ACCOUNT}" + # Message size for PubSub queue.Value in bytes max_msg_size: "${TB_QUEUE_PUBSUB_MAX_MSG_SIZE:1048576}" #in bytes + # Number of messages per consumer max_messages: "${TB_QUEUE_PUBSUB_MAX_MESSAGES:1000}" queue-properties: + # Pub/Sub properties for Core subscribers, messages which will commit after ackDeadlineInSec period can be consumed again core: "${TB_QUEUE_PUBSUB_CORE_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Version Control subscribers, messages which will commit after ackDeadlineInSec period can be consumed again notifications: "${TB_QUEUE_PUBSUB_NOTIFICATIONS_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" + # Pub/Sub properties for Transport Api subscribers, messages which will commit after ackDeadlineInSec period can be consumed again version-control: "${TB_QUEUE_PUBSUB_VC_QUEUE_PROPERTIES:ackDeadlineInSec:30;messageRetentionInSec:604800}" service_bus: + # Azure namespace namespace_name: "${TB_QUEUE_SERVICE_BUS_NAMESPACE_NAME:YOUR_NAMESPACE_NAME}" + # Azure Service Bus Shared Access Signatures key name sas_key_name: "${TB_QUEUE_SERVICE_BUS_SAS_KEY_NAME:YOUR_SAS_KEY_NAME}" + # Azure Service Bus Shared Access Signatures key sas_key: "${TB_QUEUE_SERVICE_BUS_SAS_KEY:YOUR_SAS_KEY}" + # Number of messages per a consumer max_messages: "${TB_QUEUE_SERVICE_BUS_MAX_MESSAGES:1000}" queue-properties: + # Azure Service Bus properties for Core queues core: "${TB_QUEUE_SERVICE_BUS_CORE_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Notification queues notifications: "${TB_QUEUE_SERVICE_BUS_NOTIFICATIONS_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" + # Azure Service Bus properties for Version Control queues version-control: "${TB_QUEUE_SERVICE_BUS_VC_QUEUE_PROPERTIES:lockDurationInSec:30;maxSizeInMb:1024;messageTimeToLiveInSec:604800}" rabbitmq: + # By default empty exchange_name: "${TB_QUEUE_RABBIT_MQ_EXCHANGE_NAME:}" + # RabbitMQ host used to establish connection host: "${TB_QUEUE_RABBIT_MQ_HOST:localhost}" + # RabbitMQ host used to establish a connection port: "${TB_QUEUE_RABBIT_MQ_PORT:5672}" + # Virtual hosts provide logical grouping and separation of resources virtual_host: "${TB_QUEUE_RABBIT_MQ_VIRTUAL_HOST:/}" + # Username for RabbitMQ user account username: "${TB_QUEUE_RABBIT_MQ_USERNAME:YOUR_USERNAME}" + # User password for RabbitMQ user account password: "${TB_QUEUE_RABBIT_MQ_PASSWORD:YOUR_PASSWORD}" + # Network connection between clients and RabbitMQ nodes can fail. RabbitMQ Java client supports automatic recovery of connections and topology (queues, exchanges, bindings, and consumers) automatic_recovery_enabled: "${TB_QUEUE_RABBIT_MQ_AUTOMATIC_RECOVERY_ENABLED:false}" + # The connection timeout for the RabbitMQ connection factory connection_timeout: "${TB_QUEUE_RABBIT_MQ_CONNECTION_TIMEOUT:60000}" + # RabbitMQ has a timeout for connection handshake. When clients run in heavily constrained environments, it may be necessary to increase the timeout handshake_timeout: "${TB_QUEUE_RABBIT_MQ_HANDSHAKE_TIMEOUT:10000}" queue-properties: + # RabbitMQ properties for Core queues core: "${TB_QUEUE_RABBIT_MQ_CORE_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Transport API queues transport-api: "${TB_QUEUE_RABBIT_MQ_TA_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" + # RabbitMQ properties for Version Control queues version-control: "${TB_QUEUE_RABBIT_MQ_VC_QUEUE_PROPERTIES:x-max-length-bytes:1048576000;x-message-ttl:604800000}" partitions: hash_function_name: "${TB_QUEUE_PARTITIONS_HASH_FUNCTION_NAME:murmur3_128}" # murmur3_32, murmur3_128 or sha256 core: + # Default topic name of Kafka, RabbitMQ, etc. queue topic: "${TB_QUEUE_CORE_TOPIC:tb_core}" + # Interval in milliseconds to poll messages by Core microservices poll-interval: "${TB_QUEUE_CORE_POLL_INTERVAL_MS:25}" + # Amount of partitions used by Core microservices partitions: "${TB_QUEUE_CORE_PARTITIONS:10}" + # Timeout for processing a message pack by Core microservices pack-processing-timeout: "${TB_QUEUE_CORE_PACK_PROCESSING_TIMEOUT_MS:2000}" ota: + # Default topic name for OTA updates topic: "${TB_QUEUE_CORE_OTA_TOPIC:tb_ota_package}" + # The interval of processing the OTA updates for devices. Used to avoid any harm to the network due to many parallel OTA updates pack-interval-ms: "${TB_QUEUE_CORE_OTA_PACK_INTERVAL_MS:60000}" + # The size of OTA updates notifications fetched from the queue. The queue stores pairs of firmware and device ids pack-size: "${TB_QUEUE_CORE_OTA_PACK_SIZE:100}" + # Stats topic name for queue Kafka, RabbitMQ, etc. usage-stats-topic: "${TB_QUEUE_US_TOPIC:tb_usage_stats}" stats: + # Enable/disable statistics for Core microservices enabled: "${TB_QUEUE_CORE_STATS_ENABLED:true}" + # Statistics printing interval for Core microservices print-interval-ms: "${TB_QUEUE_CORE_STATS_PRINT_INTERVAL_MS:60000}" vc: + # Default topic name for Kafka, RabbitMQ, etc. topic: "${TB_QUEUE_VC_TOPIC:tb_version_control}" + # Number of partitions to associate with this queue. Used for scaling the number of messages that can be processed in parallel partitions: "${TB_QUEUE_VC_PARTITIONS:10}" + # Interval in milliseconds between polling of the messages if no new messages arrive poll-interval: "${TB_QUEUE_VC_INTERVAL_MS:25}" + # Timeout before retrying all failed and timed-out messages from the processing pack pack-processing-timeout: "${TB_QUEUE_VC_PACK_PROCESSING_TIMEOUT_MS:180000}" + # Queue settings for Kafka, RabbitMQ, etc. Limit for single message size msg-chunk-size: "${TB_QUEUE_VC_MSG_CHUNK_SIZE:250000}" +# Version control parameters vc: # Pool size for handling export tasks thread_pool_size: "${TB_VC_POOL_SIZE:2}" git: # Pool size for handling the git IO operations io_pool_size: "${TB_VC_GIT_POOL_SIZE:3}" + # Default storing repository path repositories-folder: "${TB_VC_GIT_REPOSITORIES_FOLDER:${java.io.tmpdir}/repositories}" # Usage statistics parameters usage: stats: report: + # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" + # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" + # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" +# Metrics parameters metrics: # Enable/disable actuator metrics. enabled: "${METRICS_ENABLED:false}" @@ -194,6 +286,7 @@ metrics: # Metrics percentiles returned by actuator for timer metrics. List of double values (divided by ,). percentiles: "${METRICS_TIMER_PERCENTILES:0.5}" +# General management parameters management: endpoints: web: @@ -201,11 +294,13 @@ management: # Expose metrics endpoint (use value 'prometheus' to enable prometheus metrics). include: '${METRICS_ENDPOINTS_EXPOSE:info}' +# Service common properties service: - type: "${TB_SERVICE_TYPE:tb-vc-executor}" + type: "${TB_SERVICE_TYPE:tb-vc-executor}" # service type # Unique id for this service (autogenerated if empty) id: "${TB_SERVICE_ID:}" +# Notification system parameters notification_system: rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' diff --git a/tools/src/main/python/check_yml_file.py b/tools/src/main/python/check_yml_file.py index 0aca5e41af..ea848c8cc8 100644 --- a/tools/src/main/python/check_yml_file.py +++ b/tools/src/main/python/check_yml_file.py @@ -122,7 +122,8 @@ if __name__ == '__main__': "transport/mqtt/src/main/resources/tb-mqtt-transport.yml", "transport/coap/src/main/resources/tb-coap-transport.yml", "transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml", - "transport/snmp/src/main/resources/tb-snmp-transport.yml"] + "transport/snmp/src/main/resources/tb-snmp-transport.yml", + "msa/vc-executor/src/main/resources/tb-vc-executor.yml"] total_list = [] for file in files_to_check: From 55afd4df5da537a11d8d823111eb6a5759aa784a Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 12 Oct 2023 17:14:57 +0300 Subject: [PATCH 163/267] updated github action --- .github/workflows/check-configuration-files.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/check-configuration-files.yml b/.github/workflows/check-configuration-files.yml index bccf181bf1..0b292ded79 100644 --- a/.github/workflows/check-configuration-files.yml +++ b/.github/workflows/check-configuration-files.yml @@ -22,6 +22,13 @@ on: pull_request: paths: - 'application/src/main/resources/thingsboard.yml' + - 'transport/http/src/main/resources/tb-http-transport.yml' + - 'transport/http/src/main/resources/tb-mqtt-transport.yml' + - 'transport/http/src/main/resources/tb-coap-transport.yml' + - 'transport/http/src/main/resources/tb-lwm2m-transport.yml' + - 'transport/http/src/main/resources/tb-snmp-transport.yml' + - 'msa/vc-executor/src/main/resources/tb-vc-executor.yml' + jobs: build: name: Check thingsboard.yml file From 39aa07043a107e024ed2da9bfa6715a7bad2209c Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 12 Oct 2023 17:25:53 +0300 Subject: [PATCH 164/267] UI: Implement 'Signal strength' widget. Add 'Status indicators' widgets bundle. --- .../json/system/widget_bundles/cards.json | 1 - .../widget_bundles/status_indicators.json | 14 + .../system/widget_types/battery_level.json | 5 +- .../system/widget_types/signal_strength.json | 29 ++ .../DefaultSystemDataLoaderService.java | 1 + .../basic/basic-widget-config.module.ts | 12 +- ...ignal-strength-basic-config.component.html | 197 +++++++++ .../signal-strength-basic-config.component.ts | 316 ++++++++++++++ .../signal-strength-widget.component.html | 40 ++ .../signal-strength-widget.component.scss | 90 ++++ .../signal-strength-widget.component.ts | 387 ++++++++++++++++++ .../signal-strength-widget.models.ts | 141 +++++++ ...al-strength-widget-settings.component.html | 121 ++++++ ...gnal-strength-widget-settings.component.ts | 167 ++++++++ .../lib/settings/widget-settings.module.ts | 12 +- .../widget/widget-components.module.ts | 7 +- .../shared/models/widget-settings.models.ts | 10 +- .../assets/locale/locale.constant-en_US.json | 16 + .../signal-strength/cellular-bar-layout.svg | 31 ++ .../widget/signal-strength/wifi-layout.svg | 36 ++ 20 files changed, 1620 insertions(+), 13 deletions(-) create mode 100644 application/src/main/data/json/system/widget_bundles/status_indicators.json create mode 100644 application/src/main/data/json/system/widget_types/signal_strength.json create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.ts create mode 100644 ui-ngx/src/assets/widget/signal-strength/cellular-bar-layout.svg create mode 100644 ui-ngx/src/assets/widget/signal-strength/wifi-layout.svg 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 45f7659c51..f07f1e858e 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -11,7 +11,6 @@ "cards.value_card", "cards.horizontal_value_card", "cards.aggregated_value_card", - "battery_level", "cards.label_widget", "cards.dashboard_state_widget", "cards.qr_code", diff --git a/application/src/main/data/json/system/widget_bundles/status_indicators.json b/application/src/main/data/json/system/widget_bundles/status_indicators.json new file mode 100644 index 0000000000..e175ffa5bb --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/status_indicators.json @@ -0,0 +1,14 @@ +{ + "widgetsBundle": { + "alias": "status_indicators", + "title": "Status indicators", + "image": "data:image/png;base64,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", + "description": "Contains widgets displaying battery level and signal strength.", + "externalId": null, + "name": "Status indicators" + }, + "widgetTypeFqns": [ + "battery_level", + "signal_strength" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/battery_level.json b/application/src/main/data/json/system/widget_types/battery_level.json index 41daab9274..695a0dc525 100644 --- a/application/src/main/data/json/system/widget_types/battery_level.json +++ b/application/src/main/data/json/system/widget_types/battery_level.json @@ -17,7 +17,8 @@ "settingsDirective": "tb-battery-level-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-battery-level-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"batteryLevel\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"layout\":\"vertical_solid\",\"showValue\":true,\"autoScaleValueSize\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"batteryLevelColor\":{\"color\":\"rgba(92, 223, 144, 1)\",\"type\":\"range\",\"rangeList\":[{\"from\":0,\"to\":25,\"color\":\"rgba(227, 71, 71, 1)\"},{\"from\":25,\"to\":50,\"color\":\"rgba(246, 206, 67, 1)\"},{\"from\":50,\"to\":100,\"color\":\"rgba(92, 223, 144, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"batteryShapeColor\":{\"color\":\"rgba(92, 223, 144, 0.32)\",\"type\":\"range\",\"rangeList\":[{\"from\":0,\"to\":25,\"color\":\"rgba(227, 71, 71, 0.32)\"},{\"from\":25,\"to\":50,\"color\":\"rgba(246, 206, 67, 0.32)\"},{\"from\":50,\"to\":100,\"color\":\"rgba(92, 223, 144, 0.32)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"}},\"title\":\"Battery level\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"batteryLevel\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"layout\":\"vertical_solid\",\"showValue\":true,\"autoScaleValueSize\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":20,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"24px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"batteryLevelColor\":{\"color\":\"rgba(92, 223, 144, 1)\",\"type\":\"range\",\"rangeList\":[{\"from\":0,\"to\":25,\"color\":\"rgba(227, 71, 71, 1)\"},{\"from\":25,\"to\":50,\"color\":\"rgba(246, 206, 67, 1)\"},{\"from\":50,\"to\":100,\"color\":\"rgba(92, 223, 144, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"batteryShapeColor\":{\"color\":\"rgba(92, 223, 144, 0.32)\",\"type\":\"range\",\"rangeList\":[{\"from\":0,\"to\":25,\"color\":\"rgba(227, 71, 71, 0.32)\"},{\"from\":25,\"to\":50,\"color\":\"rgba(246, 206, 67, 0.32)\"},{\"from\":50,\"to\":100,\"color\":\"rgba(92, 223, 144, 0.32)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"sectionsCount\":4},\"title\":\"Battery level\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:battery-high\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/signal_strength.json b/application/src/main/data/json/system/widget_types/signal_strength.json new file mode 100644 index 0000000000..90c051c803 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/signal_strength.json @@ -0,0 +1,29 @@ +{ + "fqn": "signal_strength", + "name": "Signal strength", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Presents the current signal strength as WiFi or Cellular Bar.", + "descriptor": { + "type": "latest", + "sizeX": 2.5, + "sizeY": 2.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.signalStrengthWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.signalStrengthWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '200px',\n previewHeight: '200px',\n embedTitlePanel: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-signal-strength-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-signal-strength-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"rssi\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"if (!prevValue) {\\n prevValue = Math.random() * -96;\\n}\\nvar value = prevValue + (Math.random() * 60 - 30);\\nif (value > 0) {\\n\\tvalue = 0;\\n} else if (value < -96) {\\n value = -96;\\n}\\nlet rand = Math.random();\\nreturn rand < 0.2 ? (rand < 0.1 ? -101 : '') : value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"wifi\",\"showDate\":false,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"activeBarsColor\":{\"color\":\"rgba(92, 223, 144, 1)\",\"type\":\"range\",\"rangeList\":[{\"to\":-85,\"color\":\"rgba(227, 71, 71, 1)\"},{\"from\":-85,\"to\":-70,\"color\":\"rgba(255, 122, 0, 1)\"},{\"from\":-70,\"to\":-55,\"color\":\"rgba(246, 206, 67, 1)\"},{\"from\":-55,\"color\":\"rgba(92, 223, 144, 1)\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"inactiveBarsColor\":\"rgba(224, 224, 224, 1)\",\"showTooltip\":true,\"showTooltipValue\":true,\"tooltipValueFont\":{\"family\":\"Roboto\",\"size\":13,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"16px\"},\"tooltipValueColor\":\"rgba(0,0,0,0.76)\",\"showTooltipDate\":true,\"tooltipDateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"tooltipDateFont\":{\"family\":\"Roboto\",\"size\":13,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"16px\"},\"tooltipDateColor\":\"rgba(0,0,0,0.76)\",\"tooltipBackgroundColor\":\"rgba(255,255,255,0.72)\",\"tooltipBackgroundBlur\":3,\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Signal strength\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"dBm\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"signal_cellular_alt\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "wifi", + "signal", + "cellular", + "rssi" + ] +} \ No newline at end of file diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index a40913a281..0bb9d67c07 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -533,6 +533,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("tables"); this.deleteSystemWidgetBundle("count_widgets"); this.deleteSystemWidgetBundle("weather_widgets"); + this.deleteSystemWidgetBundle("status_indicators"); installScripts.loadSystemWidgets(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 3cc2eddb7d..639ede30f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -61,6 +61,9 @@ import { import { WindSpeedDirectionBasicConfigComponent } from '@home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component'; +import { + SignalStrengthBasicConfigComponent +} from '@home/components/widget/config/basic/indicator/signal-strength-basic-config.component'; @NgModule({ declarations: [ @@ -79,7 +82,8 @@ import { AlarmCountBasicConfigComponent, EntityCountBasicConfigComponent, BatteryLevelBasicConfigComponent, - WindSpeedDirectionBasicConfigComponent + WindSpeedDirectionBasicConfigComponent, + SignalStrengthBasicConfigComponent ], imports: [ CommonModule, @@ -102,7 +106,8 @@ import { AlarmCountBasicConfigComponent, EntityCountBasicConfigComponent, BatteryLevelBasicConfigComponent, - WindSpeedDirectionBasicConfigComponent + WindSpeedDirectionBasicConfigComponent, + SignalStrengthBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -119,5 +124,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + + + +
+
widget-config.appearance
+ + + {{ signalStrengthLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widget-config.title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.signal-strength.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.signal-strength.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.signal-strength.active-bars-color' | translate }}
+ + +
+
+
{{ 'widgets.signal-strength.inactive-bars-color' | translate }}
+ + +
+
+
+ + + + + {{ 'widgets.signal-strength.tooltip' | translate }} + + + + +
+ + {{ 'widgets.signal-strength.value' | translate }} + +
+ + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+ + {{ 'widgets.signal-strength.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.signal-strength.background-color' | translate }}
+ + +
+
+
widgets.signal-strength.background-blur
+ + +
px
+
+
+
+
+
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts new file mode 100644 index 0000000000..9dd0325b75 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts @@ -0,0 +1,316 @@ +/// +/// Copyright © 2016-2023 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, Injector } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + datasourcesHasAggregation, + datasourcesHasOnlyComparisonAggregation, + WidgetConfig, +} from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; +import { formatValue, isUndefined } from '@core/utils'; +import { + cssSizeToStrSize, + DateFormatProcessor, + DateFormatSettings, + resolveCssSize +} from '@shared/models/widget-settings.models'; +import { + signalStrengthDefaultSettings, + signalStrengthLayoutImages, + signalStrengthLayouts, + signalStrengthLayoutTranslations, + SignalStrengthWidgetSettings +} from '@home/components/widget/lib/indicator/signal-strength-widget.models'; + +@Component({ + selector: 'tb-signal-strength-basic-config', + templateUrl: './signal-strength-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class SignalStrengthBasicConfigComponent extends BasicWidgetConfigComponent { + + public get displayTimewindowConfig(): boolean { + const datasources = this.signalStrengthWidgetConfigForm.get('datasources').value; + return datasourcesHasAggregation(datasources); + } + + public onlyHistoryTimewindow(): boolean { + const datasources = this.signalStrengthWidgetConfigForm.get('datasources').value; + return datasourcesHasOnlyComparisonAggregation(datasources); + } + + signalStrengthLayouts = signalStrengthLayouts; + + signalStrengthLayoutTranslationMap = signalStrengthLayoutTranslations; + signalStrengthLayoutImageMap = signalStrengthLayoutImages; + + signalStrengthWidgetConfigForm: UntypedFormGroup; + + datePreviewFn = this._datePreviewFn.bind(this); + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.signalStrengthWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, [{ name: 'rssi', label: 'rssi', type: DataKeyType.timeseries }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: SignalStrengthWidgetSettings = {...signalStrengthDefaultSettings, ...(configData.config.settings || {})}; + const iconSize = resolveCssSize(configData.config.iconSize); + this.signalStrengthWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + + layout: [settings.layout, []], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + + showIcon: [configData.config.showTitleIcon, []], + iconSize: [iconSize[0], [Validators.min(0)]], + iconSizeUnit: [iconSize[1], []], + icon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + activeBarsColor: [settings.activeBarsColor, []], + inactiveBarsColor: [settings.inactiveBarsColor, []], + + showTooltip: [settings.showTooltip, []], + + showTooltipValue: [settings.showTooltipValue, []], + units: [configData.config.units, []], + decimals: [configData.config.decimals, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + + showTooltipDate: [settings.showTooltipDate, []], + tooltipDateFormat: [settings.tooltipDateFormat, []], + tooltipDateFont: [settings.tooltipDateFont, []], + tooltipDateColor: [settings.tooltipDateColor, []], + + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showIcon; + this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); + this.widgetConfig.config.titleIcon = config.icon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.layout = config.layout; + + this.widgetConfig.config.settings.showDate = config.showDate; + this.widgetConfig.config.settings.dateFormat = config.dateFormat; + this.widgetConfig.config.settings.dateFont = config.dateFont; + this.widgetConfig.config.settings.dateColor = config.dateColor; + + this.widgetConfig.config.settings.activeBarsColor = config.activeBarsColor; + this.widgetConfig.config.settings.inactiveBarsColor = config.inactiveBarsColor; + + this.widgetConfig.config.settings.showTooltip = config.showTooltip; + + this.widgetConfig.config.settings.showTooltipValue = config.showTooltipValue; + this.widgetConfig.config.units = config.units; + this.widgetConfig.config.decimals = config.decimals; + this.widgetConfig.config.settings.tooltipValueFont = config.tooltipValueFont; + this.widgetConfig.config.settings.tooltipValueColor = config.tooltipValueColor; + + this.widgetConfig.config.settings.showTooltipDate = config.showTooltipDate; + this.widgetConfig.config.settings.tooltipDateFormat = config.tooltipDateFormat; + this.widgetConfig.config.settings.tooltipDateFont = config.tooltipDateFont; + this.widgetConfig.config.settings.tooltipDateColor = config.tooltipDateColor; + + this.widgetConfig.config.settings.tooltipBackgroundColor = config.tooltipBackgroundColor; + this.widgetConfig.config.settings.tooltipBackgroundBlur = config.tooltipBackgroundBlur; + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showIcon', 'showDate', 'showTooltip', 'showTooltipValue', 'showTooltipDate']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.signalStrengthWidgetConfigForm.get('showTitle').value; + const showIcon: boolean = this.signalStrengthWidgetConfigForm.get('showIcon').value; + const showDate: boolean = this.signalStrengthWidgetConfigForm.get('showDate').value; + const showTooltip: boolean = this.signalStrengthWidgetConfigForm.get('showTooltip').value; + const showTooltipValue: boolean = this.signalStrengthWidgetConfigForm.get('showTooltipValue').value; + const showTooltipDate: boolean = this.signalStrengthWidgetConfigForm.get('showTooltipDate').value; + + if (showTitle) { + this.signalStrengthWidgetConfigForm.get('title').enable(); + this.signalStrengthWidgetConfigForm.get('titleFont').enable(); + this.signalStrengthWidgetConfigForm.get('titleColor').enable(); + this.signalStrengthWidgetConfigForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.signalStrengthWidgetConfigForm.get('iconSize').enable(); + this.signalStrengthWidgetConfigForm.get('iconSizeUnit').enable(); + this.signalStrengthWidgetConfigForm.get('icon').enable(); + this.signalStrengthWidgetConfigForm.get('iconColor').enable(); + } else { + this.signalStrengthWidgetConfigForm.get('iconSize').disable(); + this.signalStrengthWidgetConfigForm.get('iconSizeUnit').disable(); + this.signalStrengthWidgetConfigForm.get('icon').disable(); + this.signalStrengthWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.signalStrengthWidgetConfigForm.get('title').disable(); + this.signalStrengthWidgetConfigForm.get('titleFont').disable(); + this.signalStrengthWidgetConfigForm.get('titleColor').disable(); + this.signalStrengthWidgetConfigForm.get('showIcon').disable({emitEvent: false}); + this.signalStrengthWidgetConfigForm.get('iconSize').disable(); + this.signalStrengthWidgetConfigForm.get('iconSizeUnit').disable(); + this.signalStrengthWidgetConfigForm.get('icon').disable(); + this.signalStrengthWidgetConfigForm.get('iconColor').disable(); + } + + if (showDate) { + this.signalStrengthWidgetConfigForm.get('dateFormat').enable(); + this.signalStrengthWidgetConfigForm.get('dateFont').enable(); + this.signalStrengthWidgetConfigForm.get('dateColor').enable(); + } else { + this.signalStrengthWidgetConfigForm.get('dateFormat').disable(); + this.signalStrengthWidgetConfigForm.get('dateFont').disable(); + this.signalStrengthWidgetConfigForm.get('dateColor').disable(); + } + + if (showTooltip) { + this.signalStrengthWidgetConfigForm.get('showTooltipValue').enable({emitEvent: false}); + this.signalStrengthWidgetConfigForm.get('showTooltipDate').enable({emitEvent: false}); + this.signalStrengthWidgetConfigForm.get('tooltipBackgroundColor').enable(); + this.signalStrengthWidgetConfigForm.get('tooltipBackgroundBlur').enable(); + if (showTooltipValue) { + this.signalStrengthWidgetConfigForm.get('units').enable(); + this.signalStrengthWidgetConfigForm.get('decimals').enable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueFont').enable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueColor').enable(); + } else { + this.signalStrengthWidgetConfigForm.get('units').disable(); + this.signalStrengthWidgetConfigForm.get('decimals').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueFont').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueColor').disable(); + } + if (showTooltipDate) { + this.signalStrengthWidgetConfigForm.get('tooltipDateFormat').enable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateFont').enable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateColor').enable(); + } else { + this.signalStrengthWidgetConfigForm.get('tooltipDateFormat').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateFont').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateColor').disable(); + } + } else { + this.signalStrengthWidgetConfigForm.get('showTooltipValue').disable({emitEvent: false}); + this.signalStrengthWidgetConfigForm.get('showTooltipDate').disable({emitEvent: false}); + this.signalStrengthWidgetConfigForm.get('tooltipBackgroundColor').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipBackgroundBlur').disable(); + this.signalStrengthWidgetConfigForm.get('units').disable(); + this.signalStrengthWidgetConfigForm.get('decimals').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueFont').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipValueColor').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateFormat').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateFont').disable(); + this.signalStrengthWidgetConfigForm.get('tooltipDateColor').disable(); + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.signalStrengthWidgetConfigForm.get('dateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } + + private _tooltipValuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(-76, decimals, units, true); + } + + private _tooltipDatePreviewFn(): string { + const dateFormat: DateFormatSettings = this.signalStrengthWidgetConfigForm.get('tooltipDateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, {...dateFormat, ...{hideLastUpdatePrefix: true}}); + processor.update(Date.now()); + return processor.formatted; + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html new file mode 100644 index 0000000000..a2bf74e942 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.html @@ -0,0 +1,40 @@ + +
+
+
+ +
+
+
+
+
+
+
+
+
widgets.signal-strength.value
+
{{ tooltipValueText }}
+
+
+
widgets.signal-strength.last-update
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss new file mode 100644 index 0000000000..c2c14ffb76 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.scss @@ -0,0 +1,90 @@ +/** + * Copyright © 2016-2023 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-signal-strength-panel { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + gap: 16px; + padding: 20px 24px 24px 24px; + &.tb-signal-strength-pointer { + cursor: pointer; + } + > div:not(.tb-signal-strength-overlay) { + z-index: 1; + } + .tb-signal-strength-overlay { + position: absolute; + top: 12px; + left: 12px; + bottom: 12px; + right: 12px; + } + .tb-signal-strength-title-panel { + display: flex; + flex-direction: column; + .tb-widget-title { + padding: 0; + } + } + .tb-signal-strength-content { + flex: 1; + min-width: 0; + min-height: 0; + position: relative; + .tb-signal-strength-shape { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + } + .tb-signal-strength-tooltip-container { + z-index: 10; + position: absolute; + inset: 0; + display: flex; + align-items: center; + justify-content: center; + &:hover { + .tb-signal-strength-tooltip { + opacity: 1; + } + } + .tb-signal-strength-tooltip { + position: absolute; + z-index: 20; + pointer-events: none; + border: 1px solid rgba(0, 0, 0, 0.12); + border-radius: 4px; + display: flex; + flex-direction: column; + gap: 8px; + padding: 12px; + opacity: 0; + transition: opacity .35s; + .tb-signal-strength-tooltip-row { + display: flex; + justify-content: space-between; + align-items: center; + align-self: stretch; + gap: 8px; + } + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts new file mode 100644 index 0000000000..5891f2b297 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts @@ -0,0 +1,387 @@ + +/// +/// Copyright © 2016-2023 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 { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnDestroy, + OnInit, + Renderer2, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { + backgroundStyle, + ColorProcessor, + ComponentStyle, + DateFormatProcessor, + getDataKey, + getSingleTsValue, + overlayStyle, + textStyle +} from '@shared/models/widget-settings.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { formatValue, isDefinedAndNotNull, isNumeric, isUndefinedOrNull } from '@core/utils'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { Element, G, Svg, SVG } from '@svgdotjs/svg.js'; +import { + signalBarActive, + signalStrengthDefaultSettings, + SignalStrengthLayout, + SignalStrengthWidgetSettings +} from '@home/components/widget/lib/indicator/signal-strength-widget.models'; +import tinycolor from 'tinycolor2'; +import { TranslateService } from '@ngx-translate/core'; + +const shapeWidth = 149; +const shapeHeight = 113; +const shapeAspect = shapeWidth / shapeHeight; + +@Component({ + selector: 'tb-signal-strength-widget', + templateUrl: './signal-strength-widget.component.html', + styleUrls: ['./signal-strength-widget.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterViewInit { + + @ViewChild('signalStrengthShape', {static: false}) + signalStrengthShape: ElementRef; + + @ViewChild('signalStrengthTooltip', {static: false}) + signalStrengthTooltip: ElementRef; + + settings: SignalStrengthWidgetSettings; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + layout: SignalStrengthLayout; + + activeBarsColor: ColorProcessor; + + showDate = false; + dateFormat: DateFormatProcessor; + dateStyle: ComponentStyle = {}; + + showTooltip = false; + + tooltipStyle: ComponentStyle = {}; + + showTooltipValue = false; + tooltipValueText = 'N/A'; + tooltipValueLabelStyle: ComponentStyle = { + color: 'rgba(0, 0, 0, 0.38)' + }; + tooltipValueStyle: ComponentStyle = {}; + + showTooltipDate = false; + tooltipDateFormat: DateFormatProcessor; + tooltipDateLabelStyle: ComponentStyle = { + color: 'rgba(0, 0, 0, 0.38)' + }; + tooltipDateStyle: ComponentStyle = {}; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + shapeResize$: ResizeObserver; + + hasCardClickAction = false; + + private decimals = 0; + private units = ''; + + private drawSvgShapePending = false; + private svgShape: Svg; + private bars: Element[] = Array.from(Array(4), () => null); + private centerTextElement: G; + private lastCenterText: string; + + private inactiveBarsColorHex: string; + private inactiveBarsOpacity: number; + + private rssi = -100; + private noSignal = false; + private noData = false; + + constructor(public widgetComponent: WidgetComponent, + private translate: TranslateService, + private renderer: Renderer2, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.signalStrengthWidget = this; + this.settings = {...signalStrengthDefaultSettings, ...this.ctx.settings}; + + this.layout = this.settings.layout; + + this.showDate = this.settings.showDate; + if (this.showDate) { + this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); + this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); + this.dateStyle.color = this.settings.dateColor; + } + + this.activeBarsColor = ColorProcessor.fromSettings(this.settings.activeBarsColor); + const inactiveBarsColor = tinycolor(this.settings.inactiveBarsColor); + this.inactiveBarsColorHex = inactiveBarsColor.toHexString(); + this.inactiveBarsOpacity = inactiveBarsColor.getAlpha(); + + this.showTooltip = this.settings.showTooltip && (this.settings.showTooltipValue || this.settings.showTooltipDate); + + if (this.showTooltip) { + this.tooltipStyle = { + background: this.settings.tooltipBackgroundColor, + backdropFilter: `blur(${this.settings.tooltipBackgroundBlur}px)` + }; + } + + this.showTooltipValue = this.showTooltip && this.settings.showTooltipValue; + this.showTooltipDate = this.showTooltip && this.settings.showTooltipDate; + + if (this.showTooltipValue) { + this.decimals = this.ctx.decimals; + this.units = this.ctx.units; + const dataKey = getDataKey(this.ctx.datasources); + if (isDefinedAndNotNull(dataKey?.decimals)) { + this.decimals = dataKey.decimals; + } + if (dataKey?.units) { + this.units = dataKey.units; + } + this.tooltipValueStyle = textStyle(this.settings.tooltipValueFont, '0.13px'); + this.tooltipValueStyle.color = this.settings.tooltipValueColor; + this.tooltipValueLabelStyle = {...this.tooltipValueStyle, ...this.tooltipValueLabelStyle}; + } + + if (this.showTooltipDate) { + this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, + {...this.settings.tooltipDateFormat, ...{hideLastUpdatePrefix: true}}); + this.tooltipDateStyle = textStyle(this.settings.tooltipDateFont, '0.13px'); + this.tooltipDateStyle.color = this.settings.tooltipDateColor; + this.tooltipDateLabelStyle = {...this.tooltipDateStyle, ...this.tooltipDateLabelStyle}; + } + + this.backgroundStyle = backgroundStyle(this.settings.background); + this.overlayStyle = overlayStyle(this.settings.background.overlay); + + this.hasCardClickAction = this.ctx.actionsApi.getActionDescriptors('cardClick').length > 0; + } + + ngAfterViewInit() { + if (this.drawSvgShapePending) { + this.drawSvg(); + } + } + + ngOnDestroy() { + if (this.shapeResize$) { + this.shapeResize$.disconnect(); + } + } + + public onInit() { + const borderRadius = this.ctx.$widgetElement.css('borderRadius'); + this.overlayStyle = {...this.overlayStyle, ...{borderRadius}}; + if (this.signalStrengthShape) { + this.drawSvg(); + } else { + this.drawSvgShapePending = true; + } + this.cd.detectChanges(); + } + + public onDataUpdated() { + const tsValue = getSingleTsValue(this.ctx.data); + let ts; + let value; + if (tsValue) { + ts = tsValue[0]; + value = tsValue[1]; + } else { + if (this.showTooltipValue) { + this.tooltipValueText = 'N/A'; + } + } + + this.noData = isUndefinedOrNull(value) || !isNumeric(value); + if (!this.noData) { + this.rssi = Number(value); + if (this.showTooltipValue) { + this.tooltipValueText = formatValue(value, this.decimals, this.units, true); + } + } else { + this.rssi = -100; + if (this.showTooltipValue) { + this.tooltipValueText = 'N/A'; + } + } + + this.noSignal = this.rssi <= -100; + + this.activeBarsColor.update(this.rssi); + + if (this.showDate) { + this.dateFormat.update(ts); + } + + if (this.showTooltipDate) { + this.tooltipDateFormat.update(ts); + } + + this.cd.detectChanges(); + this.renderValues(); + } + + public cardClick($event: Event) { + this.ctx.actionsApi.cardClick($event); + } + + private drawSvg() { + this.svgShape = SVG().addTo(this.signalStrengthShape.nativeElement).size(shapeWidth, shapeHeight); + this.renderer.setStyle(this.svgShape.node, 'overflow', 'visible'); + this.renderer.setStyle(this.svgShape.node, 'user-select', 'none'); + + // Draw bars + + if (this.layout === SignalStrengthLayout.wifi) { + + this.bars[0] = this.svgShape.path('m 74.5,101.5 c 4.9706,0 9,-4.0294 9,-9 0,-4.9706 -4.0294,-9 -9,-9 -4.9706,0 ' + + '-9,4.0294 -9,9 0,4.9706 4.0294,9 9,9 z').fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + + this.bars[1] = this.svgShape.path('M 100.475,69.1453 C 93.3268,62.9321 84.0946,59.5 74.5299,59.5 c -9.5647,0 -18.7969,3.4321 ' + + '-25.9455,9.6453 -0.6041,0.5111 -1.0983,1.1344 -1.4539,1.8338 -0.3556,0.6994 -0.5656,1.4609 -0.6177,2.2402 -0.0521,0.7794 ' + + '0.0547,1.5612 0.3142,2.2999 0.2595,0.7386 0.6665,1.4196 1.1974,2.0032 0.5308,0.5836 1.175,1.0582 1.8951,1.3964 0.72,0.3381 ' + + '1.5016,0.533 2.2994,0.5733 0.7977,0.0404 1.5957,-0.0747 2.3476,-0.3384 0.7519,-0.2638 1.4427,-0.671 2.0323,-1.198 ' + + '4.9407,-4.2934 11.321,-6.665 17.9311,-6.665 6.6101,0 12.9904,2.3716 17.9311,6.665 1.1957,1.0392 2.7646,1.5713 ' + + '4.3616,1.4795 1.5969,-0.0919 3.0911,-0.8003 4.1544,-1.9694 1.062,-1.1691 1.607,-2.7031 1.513,-4.2645 ' + + '-0.094,-1.5615 -0.819,-3.0225 -2.015,-4.0616 z').fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + + this.bars[2] = this.svgShape.path('m 74.5,35.5001 c -16.3337,-0.0218 -32.061,5.9702 -43.9755,16.7543 -0.6032,0.5216 ' + + '-1.0925,1.1541 -1.4391,1.8606 -0.3467,0.7065 -0.5436,1.4726 -0.5795,2.2536 -0.0358,0.7809 0.0903,1.5608 0.371,2.2941 ' + + '0.2806,0.7332 0.71,1.4051 1.2632,1.976 0.5531,0.5709 1.2188,1.0295 1.958,1.3489 0.7392,0.3194 1.5371,0.493 2.3467,0.5109 ' + + '0.8097,0.0178 1.6149,-0.1206 2.3684,-0.4071 0.7535,-0.2865 1.4402,-0.7153 2.0197,-1.2613 9.6742,-8.7299 22.4234,-13.5862 ' + + '35.6671,-13.5862 13.2437,0 25.993,4.8563 35.667,13.5862 0.58,0.546 1.266,0.9748 2.02,1.2613 0.753,0.2865 1.559,0.4249 ' + + '2.368,0.4071 0.81,-0.0179 1.608,-0.1915 2.347,-0.5109 0.739,-0.3194 1.405,-0.778 1.958,-1.3489 0.553,-0.5709 0.983,-1.2428 ' + + '1.263,-1.976 0.281,-0.7333 0.407,-1.5132 0.371,-2.2941 -0.036,-0.781 -0.233,-1.5471 -0.579,-2.2536 -0.347,-0.7065 ' + + '-0.836,-1.339 -1.44,-1.8606 ' + + 'C 106.561,41.4703 90.8337,35.4783 74.5,35.5001 Z').fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + + this.bars[3] = this.svgShape.path('M 134.464,33.9289 C 117.976,19.4835 96.6509,11.5 74.5537,11.5 c -22.0972,0 -43.422,7.9835 ' + + '-59.9102,22.4289 -0.6196,0.5198 -1.1273,1.1559 -1.493,1.871 -0.3658,0.7151 -0.5823,1.4948 -0.6368,2.2933 -0.0545,0.7984 ' + + '0.054,1.5995 0.3193,2.3562 0.2652,0.7567 0.6818,1.4536 1.2253,2.05 0.5434,0.5963 1.2028,1.08 1.9393,1.4225 0.7366,0.3426 ' + + '1.5354,0.5372 2.3496,0.5723 0.8142,0.0351 1.6273,-0.0899 2.3916,-0.3677 0.7643,-0.2778 1.4643,-0.7028 2.0589,-1.25 ' + + '14.2455,-12.4752 32.6666,-19.3694 51.7545,-19.3694 19.0879,0 37.5088,6.8942 51.7548,19.3694 1.209,1.0617 2.798,1.6084 ' + + '4.418,1.5196 1.619,-0.0887 3.137,-0.8056 4.218,-1.9929 1.081,-1.1873 1.638,-2.7477 1.547,-4.338 -0.09,-1.5903 ' + + '-0.82,-3.0802 -2.029,-4.142 z').fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + } else { + this.bars[0] = this.svgShape.rect(18, 37).radius(4).move(19, 75).fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + this.bars[1] = this.svgShape.rect(18, 61).radius(4).move(50, 50).fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + this.bars[2] = this.svgShape.rect(18, 86).radius(4).move(80, 26).fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + this.bars[3] = this.svgShape.rect(18, 111).radius(4).move(111, 1).fill(this.inactiveBarsColorHex).opacity(this.inactiveBarsOpacity); + } + + this.shapeResize$ = new ResizeObserver(() => { + this.onResize(); + }); + this.shapeResize$.observe(this.signalStrengthShape.nativeElement); + this.onResize(); + + this.renderValues(); + } + + private renderValues() { + if (this.svgShape) { + const activeBarsColor = tinycolor(this.activeBarsColor.color); + const activeBarsColorHex = activeBarsColor.toHexString(); + const activeBarsOpacity = activeBarsColor.getAlpha(); + for (let index = 0; index < this.bars.length; index++) { + const bar = this.bars[index]; + const active = signalBarActive(this.rssi, index); + const newFill = active ? activeBarsColorHex : this.inactiveBarsColorHex; + const newOpacity = active ? activeBarsOpacity : this.inactiveBarsOpacity; + if (newFill !== bar.fill() || newOpacity !== bar.opacity()) { + bar.timeline().finish(); + bar.animate(200).attr({fill: newFill, opacity: newOpacity}); + } + } + const centerText = this.noData ? 'N/A' : (this.noSignal ? this.translate.instant('widgets.signal-strength.no-signal') : ''); + this.renderCenterText(centerText); + } + } + + private renderCenterText(text: string) { + if (this.lastCenterText !== text) { + if (this.centerTextElement) { + this.centerTextElement.remove(); + this.centerTextElement = null; + } + if (text) { + this.centerTextElement = this.svgShape.group(); + const textElement = this.centerTextElement.text(text).font( + { + family: 'Roboto', + weight: '500', + style: 'normal', + size: '12px', + leading: 1.333 + } + ).fill('#fff'); + const bounds = textElement.bbox(); + this.centerTextElement.rect(bounds.width + 16, bounds.height + 8) + .move(bounds.x - 8, bounds.y - 4).radius(4).fill('#848484').insertBefore(textElement); + this.centerTextElement.center(shapeWidth / 2, shapeHeight / 2); + } + this.lastCenterText = text; + } + } + + private onResize() { + const shapeContainerWidth = this.signalStrengthShape.nativeElement.getBoundingClientRect().width; + const shapeContainerHeight = this.signalStrengthShape.nativeElement.getBoundingClientRect().height; + const shapeContainerAspect = shapeContainerWidth / shapeContainerHeight; + let scale: number; + if (shapeAspect >= shapeContainerAspect) { + scale = shapeContainerWidth / shapeWidth; + } else { + scale = shapeContainerHeight / shapeHeight; + } + this.renderer.setStyle(this.svgShape.node, 'transform', `scale(${scale})`); + if (this.showTooltip) { + const targetWidth = shapeContainerWidth; + const minAspect = 0.45; + const aspect = Math.min(shapeContainerHeight / targetWidth, minAspect); + const targetHeight = targetWidth * aspect; + const height = 80; + scale = targetHeight / height; + const width = targetWidth / scale; + this.renderer.setStyle(this.signalStrengthTooltip.nativeElement, 'width', width + 'px'); + this.renderer.setStyle(this.signalStrengthTooltip.nativeElement, 'transform', `scale(${scale})`); + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts new file mode 100644 index 0000000000..59c782f5d4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.models.ts @@ -0,0 +1,141 @@ +/// +/// Copyright © 2016-2023 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 { + BackgroundSettings, + BackgroundType, + ColorSettings, + ColorType, + DateFormatSettings, + defaultColorFunction, + Font, + lastUpdateAgoDateFormat +} from '@shared/models/widget-settings.models'; + +export enum SignalStrengthLayout { + wifi = 'wifi', + cellular_bar = 'cellular_bar' +} + +export const signalStrengthLayouts = Object.keys(SignalStrengthLayout) as SignalStrengthLayout[]; + +export const signalStrengthLayoutTranslations = new Map( + [ + [SignalStrengthLayout.wifi, 'widgets.signal-strength.layout-wifi'], + [SignalStrengthLayout.cellular_bar, 'widgets.signal-strength.layout-cellular-bar'] + ] +); + +export const signalStrengthLayoutImages = new Map( + [ + [SignalStrengthLayout.wifi, 'assets/widget/signal-strength/wifi-layout.svg'], + [SignalStrengthLayout.cellular_bar, 'assets/widget/signal-strength/cellular-bar-layout.svg'] + ] +); + +export interface SignalStrengthWidgetSettings { + layout: SignalStrengthLayout; + showDate: boolean; + dateFormat: DateFormatSettings; + dateFont: Font; + dateColor: string; + activeBarsColor: ColorSettings; + inactiveBarsColor: string; + showTooltip: boolean; + showTooltipValue: boolean; + tooltipValueFont: Font; + tooltipValueColor: string; + showTooltipDate: boolean; + tooltipDateFormat: DateFormatSettings; + tooltipDateFont: Font; + tooltipDateColor: string; + tooltipBackgroundColor: string; + tooltipBackgroundBlur: number; + background: BackgroundSettings; +} + +export const signalStrengthDefaultSettings: SignalStrengthWidgetSettings = { + layout: SignalStrengthLayout.wifi, + showDate: false, + dateFormat: lastUpdateAgoDateFormat(), + dateFont: { + family: 'Roboto', + size: 12, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '16px' + }, + dateColor: 'rgba(0, 0, 0, 0.38)', + activeBarsColor: { + color: 'rgba(92, 223, 144, 1)', + type: ColorType.range, + rangeList: [ + {to: -85, color: 'rgba(227, 71, 71, 1)'}, + {from: -85, to: -70, color: 'rgba(255, 122, 0, 1)'}, + {from: -70, to: -55, color: 'rgba(246, 206, 67, 1)'}, + {from: -55, color: 'rgba(92, 223, 144, 1)'} + ], + colorFunction: defaultColorFunction + }, + inactiveBarsColor: 'rgba(224, 224, 224, 1)', + showTooltip: true, + showTooltipValue: true, + tooltipValueFont: { + family: 'Roboto', + size: 13, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '16px' + }, + tooltipValueColor: 'rgba(0,0,0,0.76)', + showTooltipDate: true, + tooltipDateFormat: lastUpdateAgoDateFormat(), + tooltipDateFont: { + family: 'Roboto', + size: 13, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '16px' + }, + tooltipDateColor: 'rgba(0,0,0,0.76)', + tooltipBackgroundColor: 'rgba(255,255,255,0.72)', + tooltipBackgroundBlur: 3, + background: { + type: BackgroundType.color, + color: '#fff', + overlay: { + enabled: false, + color: 'rgba(255,255,255,0.72)', + blur: 3 + } + } +}; + +export const signalBarActive = (rssi: number, index: number): boolean => { + switch (index) { + case 0: + return rssi > -100; + case 1: + return rssi >= -85; + case 2: + return rssi >= -70; + case 3: + return rssi >= -55; + } +}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.html new file mode 100644 index 0000000000..e5440793e9 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.html @@ -0,0 +1,121 @@ + + +
+
widgets.signal-strength.signal-strength-card-style
+ + + {{ signalStrengthLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.signal-strength.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.signal-strength.active-bars-color' | translate }}
+ + +
+
+
{{ 'widgets.signal-strength.inactive-bars-color' | translate }}
+ + +
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
+ + + + + {{ 'widgets.signal-strength.tooltip' | translate }} + + + + +
+ + {{ 'widgets.signal-strength.value' | translate }} + +
+ + + + +
+
+
+ + {{ 'widgets.signal-strength.date' | translate }} + +
+ + + + + +
+
+
+
{{ 'widgets.signal-strength.background-color' | translate }}
+ + +
+
+
widgets.signal-strength.background-blur
+ + +
px
+
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.ts new file mode 100644 index 0000000000..e7994462b6 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component.ts @@ -0,0 +1,167 @@ +/// +/// Copyright © 2016-2023 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, Injector } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue } from '@core/utils'; +import { + signalStrengthDefaultSettings, + signalStrengthLayoutImages, + signalStrengthLayouts, + signalStrengthLayoutTranslations +} from '@home/components/widget/lib/indicator/signal-strength-widget.models'; +import { DateFormatProcessor, DateFormatSettings } from '@shared/models/widget-settings.models'; + +@Component({ + selector: 'tb-signal-strength-widget-settings', + templateUrl: './signal-strength-widget-settings.component.html', + styleUrls: ['./../widget-settings.scss'], +}) +export class SignalStrengthWidgetSettingsComponent extends WidgetSettingsComponent { + + signalStrengthLayouts = signalStrengthLayouts; + + signalStrengthLayoutTranslationMap = signalStrengthLayoutTranslations; + signalStrengthLayoutImageMap = signalStrengthLayoutImages; + + signalStrengthWidgetSettingsForm: UntypedFormGroup; + + datePreviewFn = this._datePreviewFn.bind(this); + tooltipValuePreviewFn = this._tooltipValuePreviewFn.bind(this); + tooltipDatePreviewFn = this._tooltipDatePreviewFn.bind(this); + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.signalStrengthWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...signalStrengthDefaultSettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.signalStrengthWidgetSettingsForm = this.fb.group({ + layout: [settings.layout, []], + + showDate: [settings.showDate, []], + dateFormat: [settings.dateFormat, []], + dateFont: [settings.dateFont, []], + dateColor: [settings.dateColor, []], + + activeBarsColor: [settings.activeBarsColor, []], + inactiveBarsColor: [settings.inactiveBarsColor, []], + + showTooltip: [settings.showTooltip, []], + + showTooltipValue: [settings.showTooltipValue, []], + tooltipValueFont: [settings.tooltipValueFont, []], + tooltipValueColor: [settings.tooltipValueColor, []], + + showTooltipDate: [settings.showTooltipDate, []], + tooltipDateFormat: [settings.tooltipDateFormat, []], + tooltipDateFont: [settings.tooltipDateFont, []], + tooltipDateColor: [settings.tooltipDateColor, []], + + tooltipBackgroundColor: [settings.tooltipBackgroundColor, []], + tooltipBackgroundBlur: [settings.tooltipBackgroundBlur, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showDate', 'showTooltip', 'showTooltipValue', 'showTooltipDate']; + } + + protected updateValidators(emitEvent: boolean) { + const showDate: boolean = this.signalStrengthWidgetSettingsForm.get('showDate').value; + const showTooltip: boolean = this.signalStrengthWidgetSettingsForm.get('showTooltip').value; + const showTooltipValue: boolean = this.signalStrengthWidgetSettingsForm.get('showTooltipValue').value; + const showTooltipDate: boolean = this.signalStrengthWidgetSettingsForm.get('showTooltipDate').value; + + if (showDate) { + this.signalStrengthWidgetSettingsForm.get('dateFormat').enable(); + this.signalStrengthWidgetSettingsForm.get('dateFont').enable(); + this.signalStrengthWidgetSettingsForm.get('dateColor').enable(); + } else { + this.signalStrengthWidgetSettingsForm.get('dateFormat').disable(); + this.signalStrengthWidgetSettingsForm.get('dateFont').disable(); + this.signalStrengthWidgetSettingsForm.get('dateColor').disable(); + } + + if (showTooltip) { + this.signalStrengthWidgetSettingsForm.get('showTooltipValue').enable({emitEvent: false}); + this.signalStrengthWidgetSettingsForm.get('showTooltipDate').enable({emitEvent: false}); + this.signalStrengthWidgetSettingsForm.get('tooltipBackgroundColor').enable(); + this.signalStrengthWidgetSettingsForm.get('tooltipBackgroundBlur').enable(); + if (showTooltipValue) { + this.signalStrengthWidgetSettingsForm.get('tooltipValueFont').enable(); + this.signalStrengthWidgetSettingsForm.get('tooltipValueColor').enable(); + } else { + this.signalStrengthWidgetSettingsForm.get('tooltipValueFont').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipValueColor').disable(); + } + if (showTooltipDate) { + this.signalStrengthWidgetSettingsForm.get('tooltipDateFormat').enable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateFont').enable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateColor').enable(); + } else { + this.signalStrengthWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateFont').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateColor').disable(); + } + } else { + this.signalStrengthWidgetSettingsForm.get('showTooltipValue').disable({emitEvent: false}); + this.signalStrengthWidgetSettingsForm.get('showTooltipDate').disable({emitEvent: false}); + this.signalStrengthWidgetSettingsForm.get('tooltipBackgroundColor').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipBackgroundBlur').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipValueFont').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipValueColor').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateFormat').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateFont').disable(); + this.signalStrengthWidgetSettingsForm.get('tooltipDateColor').disable(); + } + } + + private _datePreviewFn(): string { + const dateFormat: DateFormatSettings = this.signalStrengthWidgetSettingsForm.get('dateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, dateFormat); + processor.update(Date.now()); + return processor.formatted; + } + + private _tooltipValuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(-76, decimals, units, true); + } + + private _tooltipDatePreviewFn(): string { + const dateFormat: DateFormatSettings = this.signalStrengthWidgetSettingsForm.get('tooltipDateFormat').value; + const processor = DateFormatProcessor.fromSettings(this.$injector, {...dateFormat, ...{hideLastUpdatePrefix: true}}); + processor.update(Date.now()); + return processor.formatted; + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index c917527872..595b2bdc41 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -291,6 +291,9 @@ import { import { WindSpeedDirectionWidgetSettingsComponent } from '@home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component'; +import { + SignalStrengthWidgetSettingsComponent +} from '@home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component'; @NgModule({ declarations: [ @@ -398,7 +401,8 @@ import { AlarmCountWidgetSettingsComponent, EntityCountWidgetSettingsComponent, BatteryLevelWidgetSettingsComponent, - WindSpeedDirectionWidgetSettingsComponent + WindSpeedDirectionWidgetSettingsComponent, + SignalStrengthWidgetSettingsComponent ], imports: [ CommonModule, @@ -511,7 +515,8 @@ import { AlarmCountWidgetSettingsComponent, EntityCountWidgetSettingsComponent, BatteryLevelWidgetSettingsComponent, - WindSpeedDirectionWidgetSettingsComponent + WindSpeedDirectionWidgetSettingsComponent, + SignalStrengthWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -589,5 +594,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type ({ @@ -319,8 +320,13 @@ export class LastUpdateAgoDateFormatProcessor extends DateFormatProcessor { } update(ts: string| number | Date): void { - this.formatted = this.translate.instant('date.last-update-n-ago-text', - {agoText: this.dateAgoPipe.transform(ts, {applyAgo: true, short: true, textPart: true})}); + const agoText = this.dateAgoPipe.transform(ts, {applyAgo: true, short: true, textPart: true}); + if (this.settings.hideLastUpdatePrefix) { + this.formatted = agoText; + } else { + this.formatted = this.translate.instant('date.last-update-n-ago-text', + {agoText}); + } } } 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 0fdf48d12c..e9169dd85e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5060,6 +5060,22 @@ "battery-level-card-style": "Battery level card style", "sections-count": "Sections count" }, + "signal-strength": { + "value": "Value", + "last-update": "Last update", + "no-signal": "No signal", + "layout": "Layout", + "layout-wifi": "Wi-Fi", + "layout-cellular-bar": "Cellular bar", + "icon": "Icon", + "date": "Date", + "active-bars-color": "Active signal bars color", + "inactive-bars-color": "Inactive signal bars color", + "tooltip": "Tooltip", + "background-color": "Background color", + "background-blur": "Background blur", + "signal-strength-card-style": "Signal strength card style" + }, "chart": { "common-settings": "Common settings", "enable-stacking-mode": "Enable stacking mode", diff --git a/ui-ngx/src/assets/widget/signal-strength/cellular-bar-layout.svg b/ui-ngx/src/assets/widget/signal-strength/cellular-bar-layout.svg new file mode 100644 index 0000000000..78759d83db --- /dev/null +++ b/ui-ngx/src/assets/widget/signal-strength/cellular-bar-layout.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/signal-strength/wifi-layout.svg b/ui-ngx/src/assets/widget/signal-strength/wifi-layout.svg new file mode 100644 index 0000000000..938c84a227 --- /dev/null +++ b/ui-ngx/src/assets/widget/signal-strength/wifi-layout.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 043d709c839caad492ab6bd922235e96e3c00b4c Mon Sep 17 00:00:00 2001 From: rusikv Date: Thu, 12 Oct 2023 18:22:44 +0300 Subject: [PATCH 165/267] UI: fixed charts color transparency not working in hex and hsla formats --- .../src/app/modules/home/components/widget/lib/flot-widget.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 9211bc9246..9f5209b5e3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -415,7 +415,6 @@ export class TbFlot { for (let i = 0; i < this.subscription.data.length; i++) { const series = this.subscription.data[i] as TbFlotSeries; - colors.push(series.dataKey.color); const keySettings = series.dataKey.settings; series.dataKey.tooltipValueFormatFunction = tooltipValueFormatFunction; if (keySettings.tooltipValueFormatter && keySettings.tooltipValueFormatter.length) { @@ -466,8 +465,8 @@ export class TbFlot { apply: true }; } - const lineColor = tinycolor(series.dataKey.color); + colors.push(lineColor.toRgbString()); lineColor.setAlpha(.75); series.highlightColor = lineColor.toRgbString(); From d40473027da40a71512e29b5e2072e9054694aa5 Mon Sep 17 00:00:00 2001 From: deaflynx Date: Fri, 13 Oct 2023 10:38:06 +0300 Subject: [PATCH 166/267] FlotKeySettingsComponent: axisMin, axisMax allow negative values --- .../lib/settings/chart/flot-key-settings.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html index a424b61606..a6938fa086 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/chart/flot-key-settings.component.html @@ -150,13 +150,13 @@
widgets.chart.min-scale-value
- +
widgets.chart.max-scale-value
- +
From 4327b8512a4478d1928c214ef6684f4e6b4141d7 Mon Sep 17 00:00:00 2001 From: rusikv Date: Fri, 13 Oct 2023 12:06:08 +0300 Subject: [PATCH 167/267] UI: rollback translations for alarm additional info in alarm rule --- ui-ngx/src/assets/locale/locale.constant-ca_ES.json | 3 --- ui-ngx/src/assets/locale/locale.constant-cs_CZ.json | 3 --- ui-ngx/src/assets/locale/locale.constant-da_DK.json | 3 --- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 4 ---- ui-ngx/src/assets/locale/locale.constant-ko_KR.json | 3 --- ui-ngx/src/assets/locale/locale.constant-sl_SI.json | 3 --- ui-ngx/src/assets/locale/locale.constant-tr_TR.json | 3 --- ui-ngx/src/assets/locale/locale.constant-zh_CN.json | 3 --- ui-ngx/src/assets/locale/locale.constant-zh_TW.json | 3 --- 9 files changed, 28 deletions(-) diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 71d2d45224..c1cfaf6244 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -1507,9 +1507,6 @@ "condition-duration-value-required": "Cal valor de duració.", "condition-duration-time-unit-required": "Cal una unidad del temps.", "advanced-settings": "Configuració avançada", - "alarm-rule-additional-info": "Información adicional", - "edit-alarm-rule-additional-info": "Editar información adicional", - "alarm-rule-additional-info-placeholder": "Proporcione sus comentarios y ajustes aquí para mostrarlos en Detalles de alarma en Información adicional", "alarm-rule-additional-info-hint": "Suggeriment: utilitzeu ${keyName} per substituir els valors de les claus d'atribut o de telemetria que s'utilitzen en condicions de regla d'alarma.", "alarm-rule-mobile-dashboard": "Tauler de control mòbil", "alarm-rule-mobile-dashboard-hint": "Utilitzat per l'aplicació mòbil com a quadre de comandament de detalls d'alarma", 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 50b105381f..857696322b 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -1143,9 +1143,6 @@ "condition-duration-value-required": "Doba trvání je povinná.", "condition-duration-time-unit-required": "Jednotka času je povinná.", "advanced-settings": "Pokročilá nastavení", - "alarm-rule-additional-info": "Doplňující informace", - "edit-alarm-rule-additional-info": "Upravit další informace", - "alarm-rule-additional-info-placeholder": "Zde uveďte své komentáře a úpravy, aby se zobrazily v detailech alarmu v části Další informace", "alarm-rule-mobile-dashboard": "Mobilní dashboard", "alarm-rule-mobile-dashboard-hint": "Používán mobilní aplikací jako dashboard detailu alarmu", "alarm-rule-no-mobile-dashboard": "Žádný dashboard nebyl vybrán", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index 3fdaa613e9..a6a5670dba 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -1197,9 +1197,6 @@ "condition-duration-value-required": "Varighedsværdi er påkrævet.", "condition-duration-time-unit-required": "Tidsenhed er påkrævet.", "advanced-settings": "Avancerede indstillinger", - "alarm-rule-additional-info": "Yderligere information", - "edit-alarm-rule-additional-info": "Rediger yderligere oplysninger", - "alarm-rule-additional-info-placeholder": "Angiv venligst dine kommentarer og justeringer her for at vise dem i Alarmdetaljer under Yderligere info", "propagate-alarm": "Overfør alarm", "alarm-rule-relation-types-list": "Relationstyper, der skal overføres", "alarm-rule-relation-types-list-hint": "Hvis der ikke vælges Overfør relationstyper vil alarmer blive overført uden filtrering på relationstype.", 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 7ebb27d63a..756567cb6f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1509,11 +1509,7 @@ "condition-duration-value-required": "Se requiere valor de duración.", "condition-duration-time-unit-required": "Se requiere una unidad de tiempo.", "advanced-settings": "Ajustes avanzados", - "alarm-rule-additional-info": "Informació addicional", - "edit-alarm-rule-additional-info": "Editeu informació addicional", - "alarm-rule-additional-info-placeholder": "Si us plau, proporcioneu els vostres comentaris i ajustos aquí per mostrar-los a Detalls d'alarma a Informació addicional", "alarm-rule-details-hint": "Ayuda: usa ${nombredeClave} para sustituir los valores de atributos o telemetrías usadas en la condición de la regla de alarma.", - "add-alarm-rule-additional-info": "Añadir detalles", "alarm-rule-mobile-dashboard": "Panel Móvil", "alarm-rule-mobile-dashboard-hint": "Usado por la aplicación móvil como panel de detalle de alarmas", "alarm-rule-no-mobile-dashboard": "No hay panel seleccionado", 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 8a46e39466..8a4d7364d2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -1010,9 +1010,6 @@ "condition-duration-value-required": "Duration value is required.", "condition-duration-time-unit-required": "Time unit is required.", "advanced-settings": "Advanced settings", - "alarm-rule-additional-info": "추가 정보", - "edit-alarm-rule-additional-info": "추가 정보 수정", - "alarm-rule-additional-info-placeholder": "추가 정보 아래의 경보 세부정보에 표시하려면 여기에 의견과 조정 사항을 입력하세요.", "propagate-alarm": "Propagate alarm", "alarm-rule-relation-types-list": "Relation types to propagate", "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation 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 d1ea6a188e..ef15d523d9 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -1010,9 +1010,6 @@ "condition-duration-value-required": "Duration value is required.", "condition-duration-time-unit-required": "Time unit is required.", "advanced-settings": "Advanced settings", - "alarm-rule-additional-info": "Dodatne informacije", - "edit-alarm-rule-additional-info": "Uredi dodatne informacije", - "alarm-rule-additional-info-placeholder": "Tukaj navedite svoje komentarje in prilagoditve, da jih prikažete v podrobnostih alarma pod dodatnimi informacijami", "propagate-alarm": "Propagate alarm", "alarm-rule-relation-types-list": "Relation types to propagate", "alarm-rule-relation-types-list-hint": "If Propagate relation types are not selected, alarms will be propagated without filtering by relation type.", 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 4c62b2ffa6..84cb3070d1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -1146,9 +1146,6 @@ "condition-duration-value-required": "Süre değeri gerekli.", "condition-duration-time-unit-required": "Zaman birimi gerekli.", "advanced-settings": "Gelişmiş ayarlar", - "alarm-rule-additional-info": "Ilave bilgi", - "edit-alarm-rule-additional-info": "Ek bilgileri düzenle", - "alarm-rule-additional-info-placeholder": "Lütfen yorumlarınızı ve ayarlamalarınızı Ek bilgiler altındaki Alarm ayrıntılarında görüntülemek için buraya girin.", "alarm-rule-mobile-dashboard": "Mobil gösterge paneli", "alarm-rule-mobile-dashboard-hint": "Mobil uygulama tarafından alarm ayrıntıları gösterge paneli olarak kullanılır", "alarm-rule-no-mobile-dashboard": "Gösterge paneli seçilmedi", 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 0554f90d5b..af22d0758e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -1511,9 +1511,6 @@ "condition-duration-value-required": "持续时间值必填。", "condition-duration-time-unit-required": "时间单位必填。", "advanced-settings": "高级设置", - "alarm-rule-additional-info": "附加信息", - "edit-alarm-rule-additional-info": "编辑附加信息", - "alarm-rule-additional-info-placeholder": "请在此处提供您的意见和调整,以便将其显示在“附加信息”下的“警报详细信息”中", "alarm-rule-additional-info-hint": "提示: 使用 ${keyName} 来替代告警规则条件中使用的属性或遥测键的值。", "alarm-rule-mobile-dashboard": "移动端仪表板", "alarm-rule-mobile-dashboard-hint": "作为移动端告警详情仪表板使用。", 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 d5b28afc32..c965549fab 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -1308,9 +1308,6 @@ "condition-duration-value-required": "需要持續時間值。", "condition-duration-time-unit-required": "需要時間單位。", "advanced-settings": "進階設定", - "alarm-rule-additional-info": "附加資訊", - "edit-alarm-rule-additional-info": "編輯附加資訊", - "alarm-rule-additional-info-placeholder": "請在此處提供您的評論和調整,以便在附加資訊下的警報詳細資訊中顯示它們。", "alarm-rule-additional-info-hint": "提示:使用${keyName}替換警告規則條件中使用的屬性或遙測鍵的值。", "alarm-rule-mobile-dashboard": "移動儀表板", "alarm-rule-mobile-dashboard-hint": "由移動應用程序用作警告詳情儀表板", From 3a4ba1f7616721342810b91710f66ea344a49508 Mon Sep 17 00:00:00 2001 From: rusikv Date: Fri, 13 Oct 2023 12:12:12 +0300 Subject: [PATCH 168/267] UI: fix for spanish translation of alarm additional info hint --- ui-ngx/src/assets/locale/locale.constant-es_ES.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 756567cb6f..c2b95db73f 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -1509,7 +1509,7 @@ "condition-duration-value-required": "Se requiere valor de duración.", "condition-duration-time-unit-required": "Se requiere una unidad de tiempo.", "advanced-settings": "Ajustes avanzados", - "alarm-rule-details-hint": "Ayuda: usa ${nombredeClave} para sustituir los valores de atributos o telemetrías usadas en la condición de la regla de alarma.", + "alarm-rule-additional-info-hint": "Ayuda: usa ${nombredeClave} para sustituir los valores de atributos o telemetrías usadas en la condición de la regla de alarma.", "alarm-rule-mobile-dashboard": "Panel Móvil", "alarm-rule-mobile-dashboard-hint": "Usado por la aplicación móvil como panel de detalle de alarmas", "alarm-rule-no-mobile-dashboard": "No hay panel seleccionado", From e0ce0a222ea33c28dbc2160c76f7bb93ca82a46a Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Fri, 13 Oct 2023 13:10:27 +0300 Subject: [PATCH 169/267] connector rpc params hotfix --- .../widget/lib/gateway/gateway-service-rpc.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts index d3002ed748..317c547725 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts @@ -78,7 +78,7 @@ export class GatewayServiceRPCComponent implements AfterViewInit { sendCommand() { const formValues = this.commandForm.value; const commandPrefix = this.isConnector ? `${this.connectorType}_` : 'gateway_'; - this.ctx.controlApi.sendTwoWayCommand(commandPrefix+formValues.command.toLowerCase(), {},formValues.time).subscribe({ + this.ctx.controlApi.sendTwoWayCommand(commandPrefix+formValues.command.toLowerCase(), formValues.params,formValues.time).subscribe({ next: resp => this.commandForm.get('result').setValue(JSON.stringify(resp)), error: error => { console.log(error); From ef45ab4f3b838bb0b7463658a6936a5602b6eb03 Mon Sep 17 00:00:00 2001 From: Maksym Dudnik Date: Fri, 13 Oct 2023 16:41:36 +0300 Subject: [PATCH 170/267] rpc params json hotfix --- .../widget/lib/gateway/gateway-service-rpc.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts index 317c547725..a8ad61e1ec 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/gateway/gateway-service-rpc.component.ts @@ -61,7 +61,7 @@ export class GatewayServiceRPCComponent implements AfterViewInit { this.commandForm = this.fb.group({ command: [null,[Validators.required]], time: [60, [Validators.required, Validators.min(1)]], - params: [{}, [jsonRequired]], + params: ['{}', [jsonRequired]], result: [null] }); } From e4d1a5896fd738acf0dbd5bd65f4001e5b128fb2 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 13 Oct 2023 17:34:33 +0300 Subject: [PATCH 171/267] UI: Refactoring api usage dashboard - rename values --- ui-ngx/src/assets/dashboard/api_usage.json | 430 ++++-------------- .../assets/locale/locale.constant-ca_ES.json | 2 - .../assets/locale/locale.constant-cs_CZ.json | 2 - .../assets/locale/locale.constant-da_DK.json | 2 - .../assets/locale/locale.constant-en_US.json | 11 +- .../assets/locale/locale.constant-es_ES.json | 2 - .../assets/locale/locale.constant-fr_FR.json | 2 - .../assets/locale/locale.constant-ko_KR.json | 2 - .../assets/locale/locale.constant-sl_SI.json | 2 - .../assets/locale/locale.constant-tr_TR.json | 2 - .../assets/locale/locale.constant-zh_CN.json | 2 - .../assets/locale/locale.constant-zh_TW.json | 2 - 12 files changed, 94 insertions(+), 367 deletions(-) diff --git a/ui-ngx/src/assets/dashboard/api_usage.json b/ui-ngx/src/assets/dashboard/api_usage.json index 3c9259f453..b1cea42249 100644 --- a/ui-ngx/src/assets/dashboard/api_usage.json +++ b/ui-ngx/src/assets/dashboard/api_usage.json @@ -84,7 +84,7 @@ "decimals": null, "funcBody": null, "usePostProcessing": true, - "postFuncBody": "return \"{i18n:api-usage.udf-executions}\";", + "postFuncBody": "return \"{i18n:api-usage.scripts}\";", "aggregationType": "NONE" }, { @@ -107,7 +107,7 @@ "label": "tbelApiState", "color": "#3f51b5", "settings": {}, - "_hash": 0.950264191483049, + "_hash": 0.2002981454581909, "aggregationType": "NONE", "units": null, "decimals": null, @@ -119,9 +119,9 @@ "name": "tbelExecutionLimit", "type": "timeseries", "label": "tbelLimit", - "color": "#e91e63", + "color": "#ffeb3b", "settings": {}, - "_hash": 0.9618078963734347, + "_hash": 0.5039854873031677, "aggregationType": "NONE", "units": null, "decimals": null, @@ -133,9 +133,9 @@ "name": "tbelExecutionCount", "type": "timeseries", "label": "tbelCount", - "color": "#ffeb3b", + "color": "#e91e63", "settings": {}, - "_hash": 0.26695276374882493, + "_hash": 0.9506731992087107, "aggregationType": "NONE", "units": null, "decimals": null, @@ -147,9 +147,9 @@ "name": "tbelExecutionApiState", "type": "timeseries", "label": "tbelUnit", - "color": "#03a9f4", + "color": "#ffeb3b", "settings": {}, - "_hash": 0.41720010909473104, + "_hash": 0.3673530683177082, "aggregationType": "NONE", "units": null, "decimals": null, @@ -189,8 +189,8 @@ "color": "#666666", "padding": "0", "settings": { - "cardHtml": "
\n \n \n
\n
\n
\n
${title}
\n
\n
\n
\n
\n
\n
${jsUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
${tbelUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
", - "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-mdc-button-base {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mdc-button__label {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-mdc-button-base {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-mdc-button-base {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-mdc-button-base {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} \n\n" + "cardHtml": "
\n \n \n
\n
\n
\n
${title}
\n
\n
\n
\n
\n
\n
${jsUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
${tbelUnit}
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n
\n \n
\n
", + "cardCss": ".card {\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n display: flex;\n flex-direction: column;\n}\n\n.card > img {\n height: 0;\n}\n\n.card .content {\n flex: 1; \n padding: 13px 13px 0;\n display: flex;\n box-sizing: border-box;\n}\n\n.card .content .column {\n display: flex;\n flex-direction: column; \n justify-content: space-around;\n flex: 1;\n}\n\n.card .content .title-row {\n display: flex;\n flex-direction: row;\n padding-bottom: 10px;\n}\n\n.card .title {\n flex: 1;\n font-size: 20px;\n font-weight: 400;\n color: #666666;\n}\n\n.card .state {\n text-transform: uppercase;\n font-size: 20px;\n font-weight: bold;\n}\n\n.card.enabled .state {\n color: #00B260;\n}\n\n.card.warning .state {\n color: #FFAD6F;\n}\n\n.card.disabled .state {\n color: #F73243;\n}\n\n.card .bars-row {\n flex: 1;\n display: flex;\n flex-direction: row;\n}\n\n.card .bar-column {\n flex: 1;\n display: flex;\n flex-direction: column;\n}\n\n.card .bar-container {\n flex: 1;\n display: flex;\n flex-direction: column;\n justify-content: center;\n}\n\n.card .bar {\n flex: 1;\n max-height: 30px;\n margin-top: 3.5px;\n margin-bottom: 4px;\n background-color: #F0F0F0;\n border: 1px solid #DADCDB;\n border-radius: 2px;\n box-shadow: inset 0 1px 3px rgba(0, 0, 0, .2);\n}\n\n.card.enabled .bar {\n border-color: #00B260;\n background-color: #F0FBF7;\n}\n\n.card.warning .bar {\n border-color: #FFAD6F;\n background-color: #FFFAF6;\n}\n\n.card.disabled .bar {\n border-color: #F73243;\n background-color: #FFF0F0;\n}\n\n.card .bar .bar-fill {\n background-color: #F0F0F0;\n border-radius: 2px;\n height: 100%;\n width: 0%;\n}\n\n.card.enabled .bar-fill {\n background-color: #00C46C;\n}\n\n.card.warning .bar-fill {\n background-color: #FFD099;\n}\n\n.card.disabled .bar-fill {\n background-color: #FF9494;\n}\n\n.card .bar-labels {\n height: 20px;\n font-size: 16px;\n color: #666;\n display: flex;\n flex-direction: row;\n}\n\n.card .mat-mdc-button-base {\n text-transform: uppercase;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.card .mdc-button__label {\n pointer-events: none;\n}\n\n.card .action-row {\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n padding: 8px 0;\n}\n\n\n@media screen and (min-width: 960px) and (max-width: 1279px) {\n .card .title {\n font-size: 12px;\n }\n .card .state {\n font-size: 12px;\n }\n .card .unit {\n font-size: 8px;\n }\n .card .bar-labels {\n font-size: 6px;\n }\n .card .mat-mdc-button-base {\n font-size: 8px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1280px) and (max-width: 1599px) {\n .card .title {\n font-size: 14px;\n }\n .card .state {\n font-size: 14px;\n }\n .card .unit {\n font-size: 10px;\n }\n .card .bar-labels {\n font-size: 8px;\n }\n .card .mat-mdc-button-base {\n font-size: 10px;\n }\n .card .action-row {\n padding: 0;\n }\n}\n\n@media screen and (min-width: 1600px) and (max-width: 1919px) {\n .card .title {\n font-size: 16px;\n }\n .card .state {\n font-size: 16px;\n }\n .card .unit {\n font-size: 12px;\n }\n .card .bar-labels {\n font-size: 12px;\n }\n .card .mat-mdc-button-base {\n font-size: 12px;\n }\n .card .action-row {\n padding: 0;\n }\n} " }, "title": "JavaScript functions", "dropShadow": true, @@ -207,12 +207,12 @@ "actions": { "elementClick": [ { - "name": "user_defined_functions_details", + "name": "script_functions_details", "icon": "insert_chart", "useShowWidgetActionFunction": null, "showWidgetActionFunction": "return true;", "type": "openDashboardState", - "targetDashboardStateId": "user_defined_functions", + "targetDashboardStateId": "script_functions", "setEntityId": false, "stateEntityParamName": null, "openRightLayout": false, @@ -225,7 +225,8 @@ "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", - "titleTooltip": "" + "titleTooltip": "", + "displayTimewindow": true }, "row": 0, "col": 0, @@ -1341,9 +1342,9 @@ "name": "tbelExecutionCountHourly", "type": "timeseries", "label": "{i18n:api-usage.tbel-executions}", - "color": "#4CAF50", + "color": "#4caf50", "settings": {}, - "_hash": 0.9298950525272727, + "_hash": 0.6818645685001823, "aggregationType": null, "units": null, "decimals": null, @@ -1373,36 +1374,40 @@ "color": "rgba(0, 0, 0, 0.87)", "padding": "8px", "settings": { - "shadowSize": 4, - "fontColor": "#545454", + "stack": false, + "enableSelection": true, "fontSize": 10, + "fontColor": "#545454", + "showTooltip": true, + "tooltipIndividual": false, + "tooltipCumulative": false, + "hideZeros": false, + "grid": { + "verticalLines": true, + "horizontalLines": true, + "outlineWidth": 1, + "color": "#545454", + "backgroundColor": null, + "tickColor": "#DDDDDD" + }, "xaxis": { + "title": null, "showLabels": true, "color": "#545454" }, "yaxis": { - "showLabels": true, - "color": "#545454", - "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;", "min": 0, - "tickDecimals": 0 - }, - "grid": { + "max": null, + "title": null, + "showLabels": true, "color": "#545454", - "tickColor": "#DDDDDD", - "verticalLines": true, - "horizontalLines": true, - "outlineWidth": 1 + "tickSize": null, + "tickDecimals": 0, + "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;" }, - "stack": false, - "tooltipIndividual": false, "defaultBarWidth": 2400000, "barAlignment": "left", - "timeForComparison": "months", - "xaxisSecond": { - "axisPosition": "top", - "showLabels": true - }, + "comparisonEnabled": false, "showLegend": true, "legendConfig": { "direction": "column", @@ -1412,9 +1417,10 @@ "showMax": false, "showAvg": false, "showTotal": true - } + }, + "customLegendEnabled": false }, - "title": "{i18n:api-usage.user-defined-functions-hourly-activity}", + "title": "{i18n:api-usage.scripts-hourly-activity}", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -1431,7 +1437,7 @@ "useShowWidgetActionFunction": null, "showWidgetActionFunction": "return true;", "type": "openDashboardState", - "targetDashboardStateId": "user_defined_functions", + "targetDashboardStateId": "script_functions", "setEntityId": false, "stateEntityParamName": null, "openRightLayout": false, @@ -1445,7 +1451,11 @@ "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", - "titleTooltip": "" + "titleTooltip": "", + "widgetCss": "", + "pageSize": 1024, + "noDataDisplayMessage": "", + "configMode": "advanced" }, "row": 0, "col": 0, @@ -2239,6 +2249,20 @@ "funcBody": null, "usePostProcessing": null, "postFuncBody": null + }, + { + "name": "tbelExecutionCountHourly", + "type": "timeseries", + "label": "{i18n:api-usage.tbel-executions}", + "color": "#4caf50", + "settings": {}, + "_hash": 0.5212969314724616, + "aggregationType": null, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null } ] } @@ -2304,7 +2328,7 @@ "showTotal": true } }, - "title": "{i18n:api-usage.javascript-functions-daily-activity}", + "title": "{i18n:api-usage.scripts-daily-activity}", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -2318,7 +2342,10 @@ "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", - "titleTooltip": "" + "titleTooltip": "", + "widgetCss": "", + "pageSize": 1024, + "noDataDisplayMessage": "" }, "row": 0, "col": 0, @@ -2371,6 +2398,20 @@ "funcBody": null, "usePostProcessing": null, "postFuncBody": null + }, + { + "name": "tbelExecutionCount", + "type": "timeseries", + "label": "{i18n:api-usage.tbel-executions}", + "color": "#4caf50", + "settings": {}, + "_hash": 0.49748239768082403, + "aggregationType": null, + "units": null, + "decimals": null, + "funcBody": null, + "usePostProcessing": null, + "postFuncBody": null } ] } @@ -2436,7 +2477,7 @@ "showTotal": true } }, - "title": "{i18n:api-usage.javascript-functions-monthly-activity}", + "title": "{i18n:api-usage.scripts-monthly-activity}", "dropShadow": true, "enableFullscreen": true, "titleStyle": { @@ -2450,7 +2491,10 @@ "showTitleIcon": false, "iconColor": "rgba(0, 0, 0, 0.87)", "iconSize": "24px", - "titleTooltip": "" + "titleTooltip": "", + "widgetCss": "", + "pageSize": 1024, + "noDataDisplayMessage": "" }, "row": 0, "col": 0, @@ -4465,288 +4509,6 @@ "col": 0, "id": "aa875b7f-e7c8-7529-1ae7-f456211b59cc", "typeFullFqn": "system.charts.timeseries_bars_flot" - }, - "16d469c0-b3f5-d8a6-c62c-5c245c2cc865": { - "type": "timeseries", - "sizeX": 8, - "sizeY": 5, - "config": { - "datasources": [ - { - "type": "entity", - "name": null, - "entityAliasId": "40193437-33ac-3172-eefd-0b08eb849062", - "filterId": null, - "dataKeys": [ - { - "name": "tbelExecutionCountHourly", - "type": "timeseries", - "label": "{i18n:api-usage.tbel-executions}", - "color": "#4CAF50", - "settings": { - "excludeFromStacking": false, - "hideDataByDefault": false, - "disableDataHiding": false, - "removeFromLegend": false, - "showLines": false, - "fillLines": false, - "showPoints": false, - "showPointShape": "circle", - "pointShapeFormatter": "", - "showPointsLineWidth": 5, - "showPointsRadius": 3, - "showSeparateAxis": false, - "axisPosition": "left", - "thresholds": [ - { - "thresholdValueSource": "predefinedValue" - } - ], - "comparisonSettings": { - "showValuesForComparison": true - } - }, - "_hash": 0.0661644137210089, - "units": null, - "decimals": null, - "funcBody": null, - "usePostProcessing": null, - "postFuncBody": null, - "aggregationType": null - } - ], - "alarmFilterConfig": { - "statusList": [ - "ACTIVE" - ] - } - } - ], - "timewindow": { - "hideInterval": false, - "hideAggregation": false, - "hideAggInterval": false, - "selectedTab": 1, - "history": { - "historyType": 0, - "timewindowMs": 2592000000, - "interval": 86400000 - }, - "aggregation": { - "type": "SUM", - "limit": 1000 - } - }, - "showTitle": true, - "backgroundColor": "#fff", - "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", - "settings": { - "shadowSize": 4, - "fontColor": "#545454", - "fontSize": 10, - "xaxis": { - "showLabels": true, - "color": "#545454" - }, - "yaxis": { - "showLabels": true, - "color": "#545454", - "min": 0, - "tickDecimals": 0, - "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;" - }, - "grid": { - "color": "#545454", - "tickColor": "#DDDDDD", - "verticalLines": true, - "horizontalLines": true, - "outlineWidth": 1 - }, - "stack": false, - "tooltipIndividual": false, - "defaultBarWidth": 1800000, - "barAlignment": "left", - "timeForComparison": "months", - "xaxisSecond": { - "axisPosition": "top", - "showLabels": true - }, - "showLegend": true, - "legendConfig": { - "direction": "column", - "position": "bottom", - "sortDataKeys": false, - "showMin": false, - "showMax": false, - "showAvg": false, - "showTotal": true - } - }, - "title": "{i18n:api-usage.tbel-functions-daily-activity}", - "dropShadow": true, - "enableFullscreen": true, - "titleStyle": { - "fontSize": "16px", - "fontWeight": 400 - }, - "widgetStyle": {}, - "useDashboardTimewindow": false, - "actions": {}, - "displayTimewindow": true, - "showTitleIcon": false, - "iconColor": "rgba(0, 0, 0, 0.87)", - "iconSize": "24px", - "titleTooltip": "", - "widgetCss": "", - "pageSize": 1024, - "noDataDisplayMessage": "" - }, - "row": 0, - "col": 0, - "id": "16d469c0-b3f5-d8a6-c62c-5c245c2cc865", - "typeFullFqn": "system.charts.timeseries_bars_flot" - }, - "70978475-c9d4-a54d-384a-851b4bba3917": { - "type": "timeseries", - "sizeX": 8, - "sizeY": 5, - "config": { - "datasources": [ - { - "type": "entity", - "name": null, - "entityAliasId": "40193437-33ac-3172-eefd-0b08eb849062", - "filterId": null, - "dataKeys": [ - { - "name": "tbelExecutionCount", - "type": "timeseries", - "label": "{i18n:api-usage.tbel-executions}", - "color": "#4CAF50", - "settings": { - "excludeFromStacking": false, - "hideDataByDefault": false, - "disableDataHiding": false, - "removeFromLegend": false, - "showLines": false, - "fillLines": false, - "showPoints": false, - "showPointShape": "circle", - "pointShapeFormatter": "", - "showPointsLineWidth": 5, - "showPointsRadius": 3, - "showSeparateAxis": false, - "axisPosition": "left", - "thresholds": [ - { - "thresholdValueSource": "predefinedValue" - } - ], - "comparisonSettings": { - "showValuesForComparison": true - } - }, - "_hash": 0.0661644137210089, - "units": null, - "decimals": null, - "funcBody": null, - "usePostProcessing": null, - "postFuncBody": null, - "aggregationType": null - } - ], - "alarmFilterConfig": { - "statusList": [ - "ACTIVE" - ] - } - } - ], - "timewindow": { - "hideInterval": false, - "hideAggregation": false, - "hideAggInterval": false, - "selectedTab": 1, - "history": { - "historyType": 0, - "timewindowMs": 31536000000, - "interval": 1000 - }, - "aggregation": { - "type": "NONE", - "limit": 1000 - } - }, - "showTitle": true, - "backgroundColor": "#fff", - "color": "rgba(0, 0, 0, 0.87)", - "padding": "8px", - "settings": { - "shadowSize": 4, - "fontColor": "#545454", - "fontSize": 10, - "xaxis": { - "showLabels": true, - "color": "#545454" - }, - "yaxis": { - "showLabels": true, - "color": "#545454", - "min": 0, - "tickDecimals": 0, - "ticksFormatter": "var rounder = Math.pow(10, 1);\nvar powers = [\n {key: 'Q', value: Math.pow(10, 15)},\n {key: 'T', value: Math.pow(10, 12)},\n {key: 'B', value: Math.pow(10, 9)},\n {key: 'M', value: Math.pow(10, 6)},\n {key: 'K', value: 1000}\n];\n\nvar key = '';\n\nfor (var i = 0; i < powers.length; i++) {\n var reduced = value / powers[i].value;\n reduced = Math.round(reduced * rounder) / rounder;\n if (reduced >= 1) {\n value = reduced;\n key = powers[i].key;\n break;\n }\n}\nreturn value + key;" - }, - "grid": { - "color": "#545454", - "tickColor": "#DDDDDD", - "verticalLines": true, - "horizontalLines": true, - "outlineWidth": 1 - }, - "stack": false, - "tooltipIndividual": false, - "defaultBarWidth": 900000000, - "barAlignment": "left", - "timeForComparison": "months", - "xaxisSecond": { - "axisPosition": "top", - "showLabels": true - }, - "showLegend": true, - "legendConfig": { - "direction": "column", - "position": "bottom", - "sortDataKeys": false, - "showMin": false, - "showMax": false, - "showAvg": false, - "showTotal": true - } - }, - "title": "{i18n:api-usage.tbel-functions-monthly-activity}", - "dropShadow": true, - "enableFullscreen": true, - "titleStyle": { - "fontSize": "16px", - "fontWeight": 400 - }, - "widgetStyle": {}, - "useDashboardTimewindow": false, - "actions": {}, - "displayTimewindow": true, - "showTitleIcon": false, - "iconColor": "rgba(0, 0, 0, 0.87)", - "iconSize": "24px", - "titleTooltip": "", - "widgetCss": "", - "pageSize": 1024, - "noDataDisplayMessage": "" - }, - "row": 0, - "col": 0, - "id": "70978475-c9d4-a54d-384a-851b4bba3917", - "typeFullFqn": "system.charts.timeseries_bars_flot" } }, "states": { @@ -5074,35 +4836,23 @@ } } }, - "user_defined_functions": { - "name": "{i18n:api-usage.user-defined-functions}", + "script_functions": { + "name": "{i18n:api-usage.scripts}", "root": false, "layouts": { "main": { "widgets": { "5f5ca59c-e507-5301-5910-7ad8cd34df40": { - "sizeX": 12, + "sizeX": 24, "sizeY": 6, "row": 0, "col": 0 }, "ada32ee9-44ed-48d1-c368-fd0c94b7607f": { - "sizeX": 12, + "sizeX": 24, "sizeY": 6, "row": 6, "col": 0 - }, - "16d469c0-b3f5-d8a6-c62c-5c245c2cc865": { - "sizeX": 12, - "sizeY": 6, - "row": 0, - "col": 12 - }, - "70978475-c9d4-a54d-384a-851b4bba3917": { - "sizeX": 12, - "sizeY": 6, - "row": 6, - "col": 12 } }, "gridSettings": { diff --git a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json index 12b3412b8e..16b72c0700 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ca_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-ca_ES.json @@ -677,8 +677,6 @@ "executions": "Execucions", "javascript": "JavaScript", "javascript-executions": "Execucions JavaScript", - "javascript-functions-daily-activity": "Activitat diària de funcions JavaScript", - "javascript-functions-monthly-activity": "Activitat mensual de funcions JavaScript", "latest-error": "Últim error", "messages": "Missatges", "notifications": "Notificacions", 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 87c5527c7b..1c31471928 100644 --- a/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json +++ b/ui-ngx/src/assets/locale/locale.constant-cs_CZ.json @@ -488,8 +488,6 @@ "executions": "Zpracování", "javascript": "JavaScript", "javascript-executions": "JavaScript výjimky", - "javascript-functions-daily-activity": "Denní aktivita JavaScript funkcí", - "javascript-functions-monthly-activity": "Měsíční aktivita JavaScript funkcí", "latest-error": "Poslední chyba", "messages": "Zprávy", "notifications": "Notifikace", diff --git a/ui-ngx/src/assets/locale/locale.constant-da_DK.json b/ui-ngx/src/assets/locale/locale.constant-da_DK.json index c2dc6c87f7..7c6da04280 100644 --- a/ui-ngx/src/assets/locale/locale.constant-da_DK.json +++ b/ui-ngx/src/assets/locale/locale.constant-da_DK.json @@ -493,8 +493,6 @@ "executions": "Udførelser", "javascript": "JavaScript", "javascript-executions": "JavaScript-udførelser", - "javascript-functions-daily-activity": "JavaScript-funktioners daglige aktivitet", - "javascript-functions-monthly-activity": "JavaScript-funktioners månedlige aktivitet", "latest-error": "Seneste fejl", "messages": "Beskeder", "permanent-failures": "${entityName} Permanente fejl", 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 9c28f42cd8..27e1177d28 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -770,17 +770,14 @@ "email-messages-monthly-activity": "Email messages monthly activity", "exceptions": "Exceptions", "executions": "Executions", - "udf-executions": "UDF executions", - "user-defined-functions": "User-defined functions", - "user-defined-functions-hourly-activity": "User-defined functions hourly activity", + "scripts": "Scripts", + "scripts-hourly-activity": "Scripts hourly activity", + "scripts-daily-activity": "Scripts daily activity", + "scripts-monthly-activity": "Scripts monthly activity", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "tbel": "TBEL", "tbel-executions": "TBEL executions", - "tbel-functions-daily-activity": "TBEL functions daily activity", - "tbel-functions-monthly-activity": "TBEL functions monthly activity", "latest-error": "Latest Error", "messages": "Messages", "notifications": "Notifications", 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 679c60a220..6891156d75 100644 --- a/ui-ngx/src/assets/locale/locale.constant-es_ES.json +++ b/ui-ngx/src/assets/locale/locale.constant-es_ES.json @@ -772,8 +772,6 @@ "executions": "Ejecuciones", "javascript": "JavaScript", "javascript-executions": "Ejecuciones JavaScript", - "javascript-functions-daily-activity": "Actividad diaria de funciones JavaScript", - "javascript-functions-monthly-activity": "Actividad mensual de funciones JavaScript", "latest-error": "Último error", "messages": "Mensajes", "notifications": "Notificaciones", 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 acf547354e..ec97ca6047 100644 --- a/ui-ngx/src/assets/locale/locale.constant-fr_FR.json +++ b/ui-ngx/src/assets/locale/locale.constant-fr_FR.json @@ -488,8 +488,6 @@ "email-messages-monthly-activity": "Activité menuselle de courriels", "executions": "Exécutions", "javascript-executions": "Exécutions JavaScript", - "javascript-functions-daily-activity": "Activité hebdomadaire de fonctions JavaScript", - "javascript-functions-monthly-activity": "Activité mensuelle de fonctions JavaScript", "latest-error": "Dernière erreur", "notifications-email-sms": "Notifications (Coourriel/SMS)", "notifications-hourly-activity": "Activité horaire de notifications", 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 142ef1491d..a5660c5ceb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -447,8 +447,6 @@ "executions": "Executions", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "latest-error": "최근 오류", "messages": "메시지", "permanent-failures": "${entityName} Permanent Failures", 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 2c9173b78d..f2943e6145 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -447,8 +447,6 @@ "executions": "Executions", "javascript": "JavaScript", "javascript-executions": "JavaScript executions", - "javascript-functions-daily-activity": "JavaScript functions daily activity", - "javascript-functions-monthly-activity": "JavaScript functions monthly activity", "latest-error": "Latest Error", "messages": "Messages", "permanent-failures": "${entityName} Permanent Failures", 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 5f05774d94..50758fb1eb 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -488,8 +488,6 @@ "executions": "Çalıştırmalar", "javascript": "JavaScript", "javascript-executions": "JavaScript çalıştırmaları", - "javascript-functions-daily-activity": "Günlük JavaScript fonksiyonları", - "javascript-functions-monthly-activity": "Aylık JavaScript fonksiyonları", "latest-error": "Son Hata", "messages": "Mesajlar", "notifications": "Bildirimler", 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 4003705a48..b8c0a36fe0 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -715,8 +715,6 @@ "executions": "执行数", "javascript": "JavaScript", "javascript-executions": "JavaScript 执行数", - "javascript-functions-daily-activity": "每天执行的JavaScript函数", - "javascript-functions-monthly-activity": "每月执行的JavaScript函数", "latest-error": "最新错误", "messages": "消息", "notifications": "通知", 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 f3d3d13660..0091acbb61 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -563,8 +563,6 @@ "executions": "執行", "javascript": "JavaScript", "javascript-executions": "JavaScript執行", - "javascript-functions-daily-activity": "JavaScript功能每日活動", - "javascript-functions-monthly-activity": "JavaScript功能每月活動", "latest-error": "最新錯誤", "messages": "訊息", "notifications": "通知", From ec6727ff7dd530c94fdb59f71c206281fc653c83 Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Sun, 15 Oct 2023 22:38:29 +0200 Subject: [PATCH 172/267] TbCoreConsumerStats: core notifications stats by message type --- .../service/queue/TbCoreConsumerStats.java | 73 +++++++++++++++++-- .../resources/application-test.properties | 3 +- 2 files changed, 69 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java b/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java index 6f614957c4..4d195a0dec 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java @@ -36,10 +36,22 @@ public class TbCoreConsumerStats { public static final String DEVICE_CLAIMS = "claimDevice"; public static final String DEVICE_STATES = "deviceState"; public static final String SUBSCRIPTION_MSGS = "subMsgs"; - public static final String TO_CORE_NOTIFICATIONS = "coreNfs"; public static final String EDGE_NOTIFICATIONS = "edgeNfs"; public static final String DEVICE_ACTIVITIES = "deviceActivity"; + public static final String TO_CORE_NF_OTHER = "coreNfOther"; // normally, there is no messages when codebase is fine + public static final String TO_CORE_NF_COMPONENT_LIFECYCLE = "coreNfCompLfcl"; + public static final String TO_CORE_NF_DEVICE_RPC_RESPONSE = "coreNfDevRpcRsp"; + public static final String TO_CORE_NF_EDGE_EVENT_UPDATE = "coreNfEdgeUpd"; + public static final String TO_CORE_NF_EDGE_SYNC_REQUEST = "coreNfEdgeSyncReq"; + public static final String TO_CORE_NF_EDGE_SYNC_RESPONSE = "coreNfEdgeSyncResp"; + public static final String TO_CORE_NF_NOTIFICATION_RULE_PROCESSOR = "coreNfNfRlProc"; + public static final String TO_CORE_NF_QUEUE_UPDATE = "coreNfQueueUpd"; + public static final String TO_CORE_NF_QUEUE_DELETE = "coreNfQueueDel"; + public static final String TO_CORE_NF_SUBSCRIPTION_SERVICE = "coreNfSubSvc"; + public static final String TO_CORE_NF_SUBSCRIPTION_MANAGER = "coreNfSubMgr"; + public static final String TO_CORE_NF_VC_RESPONSE = "coreNfVCRsp"; + private final StatsCounter totalCounter; private final StatsCounter sessionEventCounter; private final StatsCounter getAttributesCounter; @@ -48,14 +60,25 @@ public class TbCoreConsumerStats { private final StatsCounter toDeviceRPCCallResponseCounter; private final StatsCounter subscriptionInfoCounter; private final StatsCounter claimDeviceCounter; - private final StatsCounter deviceStateCounter; private final StatsCounter subscriptionMsgCounter; - private final StatsCounter toCoreNotificationsCounter; private final StatsCounter edgeNotificationsCounter; private final StatsCounter deviceActivitiesCounter; - private final List counters = new ArrayList<>(); + private final StatsCounter toCoreNfOtherCounter; + private final StatsCounter toCoreNfComponentLifecycleCounter; + private final StatsCounter toCoreNfDeviceRpcResponseCounter; + private final StatsCounter toCoreNfEdgeEventUpdateCounter; + private final StatsCounter toCoreNfEdgeSyncRequestCounter; + private final StatsCounter toCoreNfEdgeSyncResponseCounter; + private final StatsCounter toCoreNfNotificationRuleProcessorCounter; + private final StatsCounter toCoreNfQueueUpdateCounter; + private final StatsCounter toCoreNfQueueDeleteCounter; + private final StatsCounter toCoreNfSubscriptionServiceCounter; + private final StatsCounter toCoreNfSubscriptionManagerCounter; + private final StatsCounter toCoreNfVersionControlResponseCounter; + + private final List counters = new ArrayList<>(24); public TbCoreConsumerStats(StatsFactory statsFactory) { String statsKey = StatsType.CORE.getName(); @@ -70,9 +93,23 @@ public class TbCoreConsumerStats { this.claimDeviceCounter = register(statsFactory.createStatsCounter(statsKey, DEVICE_CLAIMS)); this.deviceStateCounter = register(statsFactory.createStatsCounter(statsKey, DEVICE_STATES)); this.subscriptionMsgCounter = register(statsFactory.createStatsCounter(statsKey, SUBSCRIPTION_MSGS)); - this.toCoreNotificationsCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NOTIFICATIONS)); this.edgeNotificationsCounter = register(statsFactory.createStatsCounter(statsKey, EDGE_NOTIFICATIONS)); this.deviceActivitiesCounter = register(statsFactory.createStatsCounter(statsKey, DEVICE_ACTIVITIES)); + + // Core notification counters + this.toCoreNfOtherCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_OTHER)); + this.toCoreNfComponentLifecycleCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_COMPONENT_LIFECYCLE)); + this.toCoreNfDeviceRpcResponseCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_DEVICE_RPC_RESPONSE)); + this.toCoreNfEdgeEventUpdateCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_EDGE_EVENT_UPDATE)); + this.toCoreNfEdgeSyncRequestCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_EDGE_SYNC_REQUEST)); + this.toCoreNfEdgeSyncResponseCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_EDGE_SYNC_RESPONSE)); + this.toCoreNfNotificationRuleProcessorCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_NOTIFICATION_RULE_PROCESSOR)); + this.toCoreNfQueueUpdateCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_QUEUE_UPDATE)); + this.toCoreNfQueueDeleteCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_QUEUE_DELETE)); + this.toCoreNfSubscriptionServiceCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_SUBSCRIPTION_SERVICE)); + this.toCoreNfSubscriptionManagerCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_SUBSCRIPTION_MANAGER)); + this.toCoreNfVersionControlResponseCounter = register(statsFactory.createStatsCounter(statsKey, TO_CORE_NF_VC_RESPONSE)); + } private StatsCounter register(StatsCounter counter){ @@ -127,7 +164,31 @@ public class TbCoreConsumerStats { public void log(TransportProtos.ToCoreNotificationMsg msg) { totalCounter.increment(); - toCoreNotificationsCounter.increment(); + if (msg.hasToLocalSubscriptionServiceMsg()) { + toCoreNfSubscriptionServiceCounter.increment(); + } else if (msg.hasFromDeviceRpcResponse()) { + toCoreNfDeviceRpcResponseCounter.increment(); + } else if (!msg.getComponentLifecycleMsg().isEmpty()) { + toCoreNfComponentLifecycleCounter.increment(); + } else if (!msg.getEdgeEventUpdateMsg().isEmpty()) { + toCoreNfEdgeEventUpdateCounter.increment(); + } else if (!msg.getToEdgeSyncRequestMsg().isEmpty()) { + toCoreNfEdgeSyncRequestCounter.increment(); + } else if (!msg.getFromEdgeSyncResponseMsg().isEmpty()) { + toCoreNfEdgeSyncResponseCounter.increment(); + } else if (msg.hasQueueUpdateMsg()) { + toCoreNfQueueUpdateCounter.increment(); + } else if (msg.hasQueueDeleteMsg()) { + toCoreNfQueueDeleteCounter.increment(); + } else if (msg.hasVcResponseMsg()) { + toCoreNfVersionControlResponseCounter.increment(); + } else if (msg.hasToSubscriptionMgrMsg()) { + toCoreNfSubscriptionManagerCounter.increment(); + } else if (msg.hasNotificationRuleProcessorMsg()) { + toCoreNfNotificationRuleProcessorCounter.increment(); + } else { + toCoreNfOtherCounter.increment(); + } } public void printStats() { diff --git a/application/src/test/resources/application-test.properties b/application/src/test/resources/application-test.properties index d8943b47e9..b01ffe0d72 100644 --- a/application/src/test/resources/application-test.properties +++ b/application/src/test/resources/application-test.properties @@ -12,7 +12,6 @@ transport.lwm2m.security.trust-credentials.keystore.store_file=lwm2m/credentials # Edge disabled to speed up the context init. Will be enabled by @TestPropertySource in respective tests edges.enabled=false actors.rpc.submit_strategy=BURST -queue.rule-engine.stats.enabled=true # Transports disabled to speed up the context init. Particular transport will be enabled with @TestPropertySource in respective tests transport.http.enabled=false @@ -59,7 +58,9 @@ queue.rule-engine.queues[2].processing-strategy.retries=1 queue.rule-engine.queues[2].processing-strategy.pause-between-retries=0 queue.rule-engine.queues[2].processing-strategy.max-pause-between-retries=0 +queue.rule-engine.stats.enabled=true usage.stats.report.enabled=false +queue.core.stats.enabled=true sql.audit_logs.partition_size=24 sql.ttl.audit_logs.ttl=2592000 From 0079c6d3d002f153c55c9b05ebe889139fb2cd85 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 16 Oct 2023 12:42:39 +0300 Subject: [PATCH 173/267] renamed DeviceConnectivityUtil const --- .../DeviceConnectivityController.java | 6 ++-- .../src/main/resources/thingsboard.yml | 4 +-- .../DeviceConnectivityControllerTest.java | 32 +++++++++---------- .../dao/util/DeviceConnectivityUtil.java | 6 ++-- 4 files changed, 24 insertions(+), 24 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java index dfd8109e75..83d4d16034 100644 --- a/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java +++ b/application/src/main/java/org/thingsboard/server/controller/DeviceConnectivityController.java @@ -50,7 +50,7 @@ import static org.thingsboard.server.controller.ControllerConstants.DEVICE_ID_PA import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL; import static org.thingsboard.server.controller.ControllerConstants.PROTOCOL_PARAM_DESCRIPTION; import static org.thingsboard.server.controller.ControllerConstants.TENANT_OR_CUSTOMER_AUTHORITY_PARAGRAPH; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_FILE_PEM; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_ROOT_CERT_PEM; @RestController @TbCoreComponent @@ -129,8 +129,8 @@ public class DeviceConnectivityController extends BaseController { checkNotNull(deviceConnectivityService.getPemCertFile(protocol), protocol + " pem cert file is not found!"); return ResponseEntity.ok() - .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + CA_FILE_PEM) - .header("x-filename", CA_FILE_PEM) + .header(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=" + CA_ROOT_CERT_PEM) + .header("x-filename", CA_ROOT_CERT_PEM) .contentLength(pemCert.contentLength()) .contentType(MediaType.APPLICATION_OCTET_STREAM) .body(pemCert); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9de4ea32f2..e8338a6a5c 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1179,8 +1179,8 @@ device: host: "${DEVICE_CONNECTIVITY_MQTTS_HOST:}" # Port of mqtt transport service. If empty default port for mqtts will be used. port: "${DEVICE_CONNECTIVITY_MQTTS_PORT:8883}" - # Path to the mqtt certificate authority file - pem_cert_file: "${DEVICE_CONNECTIVITY_MQTT_SSL_PEM_CERT:cafile.pem}" + # Path to the MQTT CA root certificate file + pem_cert_file: "${DEVICE_CONNECTIVITY_MQTTS_CA_ROOT_CERT:cafile.pem}" coap: # If true coap command will be included to the list of all test commands using DEVICE_CONNECTIVITY_COAP_HOST and DEVICE_CONNECTIVITY_COAP_PORT. enabled: "${DEVICE_CONNECTIVITY_COAP_ENABLED:true}" diff --git a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java index 1a68d80753..1eaf719921 100644 --- a/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/DeviceConnectivityControllerTest.java @@ -62,14 +62,14 @@ import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTP; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.HTTPS; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTT; import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.MQTTS; -import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_FILE_PEM; +import static org.thingsboard.server.dao.util.DeviceConnectivityUtil.CA_ROOT_CERT_PEM; @TestPropertySource(properties = { "device.connectivity.https.enabled=true", "device.connectivity.http.port=8080", "device.connectivity.https.port=444", "device.connectivity.mqtts.enabled=true", - "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_FILE_PEM, + "device.connectivity.mqtts.pem_cert_file=/tmp/" + CA_ROOT_CERT_PEM, "device.connectivity.coaps.enabled=true", }) @ContextConfiguration(classes = {DeviceConnectivityControllerTest.Config.class}) @@ -202,8 +202,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t v1/devices/me/telemetry " + "-u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 " + "-t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -211,8 +211,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"", credentials.getCredentialsId())); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 -t v1/devices/me/telemetry -u %s -m \"{temperature:25}\"\"", credentials.getCredentialsId())); JsonNode linuxCoapCommands = commands.get(COAP); @@ -240,8 +240,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 " + "-t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -249,8 +249,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t %s -u %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 -t %s -u %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, credentials.getCredentialsId())); } @@ -284,8 +284,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { JsonNode mqttCommands = commands.get(MQTT); assertThat(mqttCommands.get(MQTT).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 -h localhost -p 1883 -t %s " + "-i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); - assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); - assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 " + + assertThat(mqttCommands.get(MQTTS).get(0).asText()).isEqualTo("curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download"); + assertThat(mqttCommands.get(MQTTS).get(1).asText()).isEqualTo(String.format("mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 " + "-t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); JsonNode dockerMqttCommands = commands.get(MQTT).get(DOCKER); @@ -293,8 +293,8 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { " -p 1883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); assertThat(dockerMqttCommands.get(MQTTS).asText()).isEqualTo(String.format("docker run --rm -it thingsboard/mosquitto-clients " + - "/bin/sh -c \"curl -f -S -o cafile.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + - "mosquitto_pub -d -q 1 --cafile cafile.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", + "/bin/sh -c \"curl -f -S -o ca-root.pem http://localhost:80/api/device-connectivity/mqtts/certificate/download && " + + "mosquitto_pub -d -q 1 --cafile ca-root.pem -h localhost -p 8883 -t %s -i %s -u %s -P %s -m \"{temperature:25}\"\"", DEVICE_TELEMETRY_TOPIC, clientId, userName, password)); } @@ -368,7 +368,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { @Test @DirtiesContext public void testDownloadMqttCert() throws Exception { - Path path = Files.createFile(Path.of("/tmp/" + CA_FILE_PEM)); + Path path = Files.createFile(Path.of("/tmp/" + CA_ROOT_CERT_PEM)); Files.writeString(path, CERT); try { @@ -382,7 +382,7 @@ public class DeviceConnectivityControllerTest extends AbstractControllerTest { @Test @DirtiesContext public void testDownloadMqttCertFromFileWithPrivateKey() throws Exception { - Path path = Files.createFile(Path.of("/tmp/" + CA_FILE_PEM)); + Path path = Files.createFile(Path.of("/tmp/" + CA_ROOT_CERT_PEM)); Files.writeString(path, CERT + P_KEY); try { diff --git a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java index a38d2bc2d8..d6315a2eca 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java +++ b/dao/src/main/java/org/thingsboard/server/dao/util/DeviceConnectivityUtil.java @@ -31,7 +31,7 @@ public class DeviceConnectivityUtil { public static final String MQTTS = "mqtts"; public static final String COAP = "coap"; public static final String COAPS = "coaps"; - public static final String CA_FILE_PEM = "cafile.pem"; + public static final String CA_ROOT_CERT_PEM = "ca-root.pem"; public static final String CHECK_DOCUMENTATION = "Check documentation"; public static final String JSON_EXAMPLE_PAYLOAD = "\"{temperature:25}\""; public static final String DOCKER_RUN = "docker run --rm -it "; @@ -47,7 +47,7 @@ public class DeviceConnectivityUtil { public static String getMqttPublishCommand(String protocol, String host, String port, String deviceTelemetryTopic, DeviceCredentials deviceCredentials) { StringBuilder command = new StringBuilder("mosquitto_pub -d -q 1"); if (MQTTS.equals(protocol)) { - command.append(" --cafile ").append(CA_FILE_PEM); + command.append(" --cafile ").append(CA_ROOT_CERT_PEM); } command.append(" -h ").append(host).append(port == null ? "" : " -p " + port); command.append(" -t ").append(deviceTelemetryTopic); @@ -151,7 +151,7 @@ public class DeviceConnectivityUtil { } public static String getCurlPemCertCommand(String baseUrl, String protocol) { - return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", CA_FILE_PEM, baseUrl, protocol); + return String.format("curl -f -S -o %s %s/api/device-connectivity/%s/certificate/download", CA_ROOT_CERT_PEM, baseUrl, protocol); } public static String getCoapPublishCommand(String protocol, String host, String port, DeviceCredentials deviceCredentials) { From fb5c593bb50a307b362ca4b0832e2bde8d1d42bb Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 16 Oct 2023 12:54:10 +0300 Subject: [PATCH 174/267] Edge events are processed in a separate threads to avoid blocking core consumer threads --- .../edge/DefaultEdgeNotificationService.java | 171 ++++++++++-------- .../src/main/resources/thingsboard.yml | 1 + 2 files changed, 92 insertions(+), 80 deletions(-) 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 69852e6c05..c8e0c09d50 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 @@ -22,10 +22,11 @@ import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; import org.thingsboard.common.util.JacksonUtil; -import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.audit.ActionType; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEventType; @@ -59,7 +60,7 @@ import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import java.util.UUID; import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; @Service @TbCoreComponent @@ -128,17 +129,20 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { @Autowired protected ApplicationEventPublisher eventPublisher; - private ExecutorService dbCallBackExecutor; + @Value("${actors.system.edge_dispatcher_pool_size:4}") + private int edgeDispatcherSize; + + private ExecutorService executor; @PostConstruct public void initExecutor() { - dbCallBackExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("edge-notifications")); + executor = ThingsBoardExecutors.newWorkStealingPool(edgeDispatcherSize, "edge-notifications"); } @PreDestroy public void shutdownExecutor() { - if (dbCallBackExecutor != null) { - dbCallBackExecutor.shutdownNow(); + if (executor != null) { + executor.shutdownNow(); } } @@ -157,82 +161,89 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); log.debug("[{}] Pushing notification to edge {}", tenantId, edgeNotificationMsg); - try { - EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); - ListenableFuture future; - switch (type) { - case EDGE: - future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); - break; - case ASSET: - future = assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case DEVICE: - future = deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ENTITY_VIEW: - future = entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case DASHBOARD: - future = dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case RULE_CHAIN: - future = ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case USER: - future = userProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case CUSTOMER: - future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); - break; - case DEVICE_PROFILE: - future = deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ASSET_PROFILE: - future = assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case OTA_PACKAGE: - future = otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case WIDGETS_BUNDLE: - future = widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case WIDGET_TYPE: - future = widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case QUEUE: - future = queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ALARM: - future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); - break; - case RELATION: - future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg); - break; - case TENANT: - future = tenantEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case TENANT_PROFILE: - future = tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - default: - log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); - future = Futures.immediateFuture(null); - } - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void unused) { - callback.onSuccess(); + final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); + executor.submit(() -> { + try { + if (deadline < System.nanoTime()) { + log.warn("[{}] Skipping notification message because deadline reached {}", tenantId, edgeNotificationMsg); + return; } - - @Override - public void onFailure(Throwable throwable) { - callBackFailure(tenantId, edgeNotificationMsg, callback, throwable); + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); + ListenableFuture future; + switch (type) { + case EDGE: + future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); + break; + case ASSET: + future = assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case DEVICE: + future = deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ENTITY_VIEW: + future = entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case DASHBOARD: + future = dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case RULE_CHAIN: + future = ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case USER: + future = userProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case CUSTOMER: + future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); + break; + case DEVICE_PROFILE: + future = deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ASSET_PROFILE: + future = assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case OTA_PACKAGE: + future = otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case WIDGETS_BUNDLE: + future = widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case WIDGET_TYPE: + future = widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case QUEUE: + future = queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ALARM: + future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); + break; + case RELATION: + future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg); + break; + case TENANT: + future = tenantEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case TENANT_PROFILE: + future = tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + default: + log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); + future = Futures.immediateFuture(null); } - }, dbCallBackExecutor); - } catch (Exception e) { - callBackFailure(tenantId, edgeNotificationMsg, callback, e); - } + Futures.addCallback(future, new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void unused) { + callback.onSuccess(); + } + + @Override + public void onFailure(Throwable throwable) { + callBackFailure(tenantId, edgeNotificationMsg, callback, throwable); + } + }, executor); + } catch (Exception e) { + callBackFailure(tenantId, edgeNotificationMsg, callback, e); + } + }); } private void callBackFailure(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 4a3023d48f..9fbfd2fc63 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -364,6 +364,7 @@ actors: tenant_dispatcher_pool_size: "${ACTORS_SYSTEM_TENANT_DISPATCHER_POOL_SIZE:2}" device_dispatcher_pool_size: "${ACTORS_SYSTEM_DEVICE_DISPATCHER_POOL_SIZE:4}" rule_dispatcher_pool_size: "${ACTORS_SYSTEM_RULE_DISPATCHER_POOL_SIZE:8}" + edge_dispatcher_pool_size: "${ACTORS_SYSTEM_EDGE_DISPATCHER_POOL_SIZE:4}" tenant: create_components_on_init: "${ACTORS_TENANT_CREATE_COMPONENTS_ON_INIT:true}" session: From e33c3b43a597e5a5a899bf552ac8e1a0888cca63 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 16 Oct 2023 13:36:47 +0300 Subject: [PATCH 175/267] DefaultEdgeNotificationService - onSuccess() make ASAP --- .../edge/DefaultEdgeNotificationService.java | 156 ++++++++---------- 1 file changed, 72 insertions(+), 84 deletions(-) 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 c8e0c09d50..7f52ebb94b 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 @@ -16,11 +16,7 @@ package org.thingsboard.server.service.edge; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.util.concurrent.FutureCallback; -import com.google.common.util.concurrent.Futures; -import com.google.common.util.concurrent.ListenableFuture; import lombok.extern.slf4j.Slf4j; -import org.checkerframework.checker.nullness.qual.Nullable; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; @@ -162,88 +158,80 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); log.debug("[{}] Pushing notification to edge {}", tenantId, edgeNotificationMsg); final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); - executor.submit(() -> { - try { - if (deadline < System.nanoTime()) { - log.warn("[{}] Skipping notification message because deadline reached {}", tenantId, edgeNotificationMsg); - return; - } - EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); - ListenableFuture future; - switch (type) { - case EDGE: - future = edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); - break; - case ASSET: - future = assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case DEVICE: - future = deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ENTITY_VIEW: - future = entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case DASHBOARD: - future = dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case RULE_CHAIN: - future = ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case USER: - future = userProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case CUSTOMER: - future = customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); - break; - case DEVICE_PROFILE: - future = deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ASSET_PROFILE: - future = assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case OTA_PACKAGE: - future = otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case WIDGETS_BUNDLE: - future = widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case WIDGET_TYPE: - future = widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case QUEUE: - future = queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case ALARM: - future = alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); - break; - case RELATION: - future = relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg); - break; - case TENANT: - future = tenantEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - case TENANT_PROFILE: - future = tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); - break; - default: - log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); - future = Futures.immediateFuture(null); - } - Futures.addCallback(future, new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void unused) { - callback.onSuccess(); + try { + executor.submit(() -> { + try { + if (deadline < System.nanoTime()) { + log.warn("[{}] Skipping notification message because deadline reached {}", tenantId, edgeNotificationMsg); + return; } - - @Override - public void onFailure(Throwable throwable) { - callBackFailure(tenantId, edgeNotificationMsg, callback, throwable); + EdgeEventType type = EdgeEventType.valueOf(edgeNotificationMsg.getType()); + switch (type) { + case EDGE: + edgeProcessor.processEdgeNotification(tenantId, edgeNotificationMsg); + break; + case ASSET: + assetProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case DEVICE: + deviceProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ENTITY_VIEW: + entityViewProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case DASHBOARD: + dashboardProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case RULE_CHAIN: + ruleChainProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case USER: + userProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case CUSTOMER: + customerProcessor.processCustomerNotification(tenantId, edgeNotificationMsg); + break; + case DEVICE_PROFILE: + deviceProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ASSET_PROFILE: + assetProfileProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case OTA_PACKAGE: + otaPackageProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case WIDGETS_BUNDLE: + widgetBundleProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case WIDGET_TYPE: + widgetTypeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case QUEUE: + queueProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case ALARM: + alarmProcessor.processAlarmNotification(tenantId, edgeNotificationMsg); + break; + case RELATION: + relationProcessor.processRelationNotification(tenantId, edgeNotificationMsg); + break; + case TENANT: + tenantEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + case TENANT_PROFILE: + tenantProfileEdgeProcessor.processEntityNotification(tenantId, edgeNotificationMsg); + break; + default: + log.warn("[{}] Edge event type [{}] is not designed to be pushed to edge", tenantId, type); } - }, executor); - } catch (Exception e) { - callBackFailure(tenantId, edgeNotificationMsg, callback, e); - } - }); + } catch (Exception e) { + callBackFailure(tenantId, edgeNotificationMsg, callback, e); + } + }); + callback.onSuccess(); + } catch (Exception e) { + callBackFailure(tenantId, edgeNotificationMsg, callback, e); + } } private void callBackFailure(TenantId tenantId, TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback, Throwable throwable) { From 7cd71983c9f0260b3054d1e210387f6d4cbfa84f Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Mon, 16 Oct 2023 13:51:46 +0300 Subject: [PATCH 176/267] updated yml parameters description --- .../src/main/resources/thingsboard.yml | 75 +++++++++---------- 1 file changed, 37 insertions(+), 38 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index c7d5af8a5d..32b095b52a 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -34,7 +34,7 @@ server: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${SSL_PEM_CERT:server.pem}" - # Path to the server certificate private key file. Optional by default. Required if the private key is not present in the server certificate file; + # Path to the server certificate private key file (optional). Required if the private key is not present in the server certificate file key_file: "${SSL_PEM_KEY:server_key.pem}" # Server certificate private key password (optional) key_password: "${SSL_PEM_KEY_PASSWORD:server_key_password}" @@ -68,7 +68,7 @@ server: refresh_pool_size: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_REFRESH_POOL_SIZE:1}" # Maximum number of dynamic queries per refresh interval. For example, no more than 10 alarm queries are executed by the user simultaneously in all browsers. max_alarm_queries_per_refresh_interval: "${TB_SERVER_WS_MAX_ALARM_QUERIES_PER_REFRESH_INTERVAL:10}" - # Maximum number of dynamic queries per user. For example, no more than 10 alarm widgets opened by the user simultaneously in all browsers< + # Maximum number of dynamic queries per user. For example, no more than 10 alarm widgets opened by the user simultaneously in all browsers max_per_user: "${TB_SERVER_WS_DYNAMIC_PAGE_LINK_MAX_PER_USER:10}" # Maximum number of entities returned for single entity subscription. For example, no more than 10,000 entities on the map widget max_entities_per_data_subscription: "${TB_SERVER_WS_MAX_ENTITIES_PER_DATA_SUBSCRIPTION:10000}" @@ -79,7 +79,7 @@ server: rest: server_side_rpc: # Minimum value of the server-side RPC timeout. May override value provided in the REST API call. - # Since 2.5 migration to queues, the RPC delay depends on the size of the pending messages in the queue, + # Since 2.5 migration to queues, the RPC delay depends on the size of the pending messages in the queue. # So default UI parameter of 500ms may not be sufficient for loaded environments. min_timeout: "${MIN_SERVER_SIDE_RPC_TIMEOUT:5000}" # Default value of the server-side RPC timeout. @@ -93,7 +93,7 @@ app: # Application version version: "@project.version@" -# Zookeeper connection parameters. Used for service discovery. +# Zookeeper connection parameters zk: # Enable/disable zookeeper discovery service. enabled: "${ZOOKEEPER_ENABLED:false}" @@ -160,18 +160,18 @@ security: # Mail settings parameters mail: oauth2: - # Interval to check that the refresh token will expire in seconds(by default, 1 day). + # Interval for checking refresh token expiration in seconds(by default, 1 day). refreshTokenCheckingInterval: "${REFRESH_TOKEN_EXPIRATION_CHECKING_INTERVAL:86400}" # Usage statistics parameters usage: stats: report: - # Enable/Disable the collection of statistics about API usage. Collected on a system and tenant level by default + # Enable/Disable the collection of API usage statistics. Collected on a system and tenant level by default enabled: "${USAGE_STATS_REPORT_ENABLED:true}" - # Enable/Disable collection of statistics about API usage on a customer level + # Enable/Disable the collection of API usage statistics on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" - # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds + # Statistics reporting interval, set to send summarized data every 10 seconds by default interval: "${USAGE_STATS_REPORT_INTERVAL:10}" check: # Interval of checking the start of the next cycle and re-enabling the blocked tenants/customers @@ -197,7 +197,7 @@ ui: database: ts_max_intervals: "${DATABASE_TS_MAX_INTERVALS:700}" # Max number of DB queries generated by a single API call to fetch telemetry records ts: - type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra or timescale) + type: "${DATABASE_TS_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale) ts_latest: type: "${DATABASE_TS_LATEST_TYPE:sql}" # cassandra, sql, or timescale (for hybrid mode, DATABASE_TS_TYPE value should be cassandra, or timescale) @@ -276,7 +276,7 @@ cassandra: # Returns the hint to the size of the underlying buffers for outgoing network I/O. By default, this option is not set by the driver. The actual value will be the default from the underlying Netty transport send_buffer_size: "${CASSANDRA_SOCKET_SEND_BUFFER_SIZE:}" - # Cassandra cluster connection query parameters # + # Cassandra cluster connection query parameters query: # Consistency levels in Cassandra can be configured to manage availability versus data accuracy. The consistency level defaults to ONE for all write and read operations read_consistency_level: "${CASSANDRA_READ_CONSISTENCY_LEVEL:ONE}" @@ -374,12 +374,12 @@ sql: batch_threads: "${SQL_TIMESCALE_BATCH_THREADS:3}" # batch thread count has to be a prime number like 3 or 5 to gain perfect hash distribution ttl: ts: - # The parameter to specify whether to use TTL (Time To Live) for timeseries records + # Enable/disable TTL (Time To Live) for timeseries records enabled: "${SQL_TTL_TS_ENABLED:true}" execution_interval_ms: "${SQL_TTL_TS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day ts_key_value_ttl: "${SQL_TTL_TS_TS_KEY_VALUE_TTL:0}" # Number of seconds events: - # The parameter to specify whether to use TTL (Time To Live) for event records + # Enable/disable TTL (Time To Live) for event records enabled: "${SQL_TTL_EVENTS_ENABLED:true}" execution_interval_ms: "${SQL_TTL_EVENTS_EXECUTION_INTERVAL:3600000}" # Number of milliseconds (max random initial delay and fixed period). # Number of seconds. TTL is disabled by default. The accuracy of the cleanup depends on the sql.events.partition_size parameter. @@ -387,21 +387,21 @@ sql: # Number of seconds. The current value corresponds to one week. The accuracy of the cleanup depends on the sql.events.debug_partition_size parameter. debug_events_ttl: "${SQL_TTL_EVENTS_DEBUG_EVENTS_TTL:604800}" edge_events: - enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for egde event records + enabled: "${SQL_TTL_EDGE_EVENTS_ENABLED:true}" # Enable/disable TTL (Time To Live) for edge event records execution_interval_ms: "${SQL_TTL_EDGE_EVENTS_EXECUTION_INTERVAL:86400000}" # Number of milliseconds. The current value corresponds to one day edge_events_ttl: "${SQL_TTL_EDGE_EVENTS_TTL:2628000}" # Number of seconds. The current value corresponds to one month alarms: checking_interval: "${SQL_ALARMS_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours removal_batch_size: "${SQL_ALARMS_TTL_REMOVAL_BATCH_SIZE:3000}" # To delete outdated alarms not all at once but in batches rpc: - enabled: "${SQL_TTL_RPC_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for rpc call records + enabled: "${SQL_TTL_RPC_ENABLED:true}" # Enable/disable TTL (Time To Live) for rpc call records checking_interval: "${SQL_RPC_TTL_CHECKING_INTERVAL:7200000}" # Number of milliseconds. The current value corresponds to two hours audit_logs: - enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for audit log records + enabled: "${SQL_TTL_AUDIT_LOGS_ENABLED:true}" # Enable/disable TTL (Time To Live) for audit log records ttl: "${SQL_TTL_AUDIT_LOGS_SECS:0}" # Disabled by default. The accuracy of the cleanup depends on the sql.audit_logs.partition_size checking_interval_ms: "${SQL_TTL_AUDIT_LOGS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day notifications: - enabled: "${SQL_TTL_NOTIFICATIONS_ENABLED:true}" # The parameter to specify whether to use TTL (Time To Live) for notification center records + enabled: "${SQL_TTL_NOTIFICATIONS_ENABLED:true}" # Enable/disable TTL (Time To Live) for notification center records ttl: "${SQL_TTL_NOTIFICATIONS_SECS:2592000}" # Default value - 30 days checking_interval_ms: "${SQL_TTL_NOTIFICATIONS_CHECKING_INTERVAL_MS:86400000}" # Default value - 1 day relations: @@ -476,7 +476,7 @@ actors: # Actors statistic persistence frequency in milliseconds persist_frequency: "${ACTORS_STATISTICS_PERSIST_FREQUENCY:3600000}" -# Cache parameters +# Cache settings parameters cache: # caffeine or redis type: "${CACHE_TYPE:caffeine}" @@ -486,7 +486,7 @@ cache: enabled: "${CACHE_ATTRIBUTES_ENABLED:true}" specs: relations: - timeToLiveInMinutes: "${CACHE_SPECS_RELATIONS_TTL:1440}" # Relations cache max size + timeToLiveInMinutes: "${CACHE_SPECS_RELATIONS_TTL:1440}" # Relations cache TTL maxSize: "${CACHE_SPECS_RELATIONS_MAX_SIZE:10000}" # 0 means the cache is disabled deviceCredentials: timeToLiveInMinutes: "${CACHE_SPECS_DEVICE_CREDENTIALS_TTL:1440}" # Device credentials cache TTL @@ -516,7 +516,7 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" # Tenant cache TTL maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" # 0 means the cache is disabled tenantsExist: - # environment variables are intentionally the same as in 'tenants' cache to be equal. + # Environment variables are intentionally the same as in 'tenants' cache to be equal. timeToLiveInMinutes: "${CACHE_SPECS_TENANTS_TTL:1440}" maxSize: "${CACHE_SPECS_TENANTS_MAX_SIZE:10000}" # 0 means the cache is disabled deviceProfiles: @@ -526,7 +526,7 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_ASSET_PROFILES_TTL:1440}" # Asset profile cache TTL maxSize: "${CACHE_SPECS_ASSET_PROFILES_MAX_SIZE:10000}" # 0 means the cache is disabled notificationSettings: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}" # Noification settings cache TTL + timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_SETTINGS_TTL:10}" # Notification settings cache TTL maxSize: "${CACHE_SPECS_NOTIFICATION_SETTINGS_MAX_SIZE:1000}" # 0 means the cache is disabled sentNotifications: timeToLiveInMinutes: "${CACHE_SPECS_SENT_NOTIFICATIONS_TTL:1440}" # Sent notifications cache TTL @@ -554,7 +554,7 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_TTL:1440}" # Autocommit settings cache TTL maxSize: "${CACHE_SPECS_AUTO_COMMIT_SETTINGS_MAX_SIZE:10000}" # 0 means the cache is disabled twoFaVerificationCodes: - timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}" # Two fa carification codes cache TTL + timeToLiveInMinutes: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_TTL:60}" # Two factor verification codes cache TTL maxSize: "${CACHE_SPECS_TWO_FA_VERIFICATION_CODES_MAX_SIZE:100000}" # 0 means the cache is disabled versionControlTask: timeToLiveInMinutes: "${CACHE_SPECS_VERSION_CONTROL_TASK_TTL:20}" # Version control task cache TTL @@ -575,9 +575,9 @@ cache: timeToLiveInMinutes: "${CACHE_SPECS_ALARM_TYPES_TTL:60}" # Alarm types cache TTL maxSize: "${CACHE_SPECS_ALARM_TYPES_MAX_SIZE:10000}" # 0 means the cache is disabled - # deliberately placed outside the 'specs' group above + # Deliberately placed outside the 'specs' group above notificationRules: - timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}" # notification rules cache TTL + timeToLiveInMinutes: "${CACHE_SPECS_NOTIFICATION_RULES_TTL:30}" # Notification rules cache TTL maxSize: "${CACHE_SPECS_NOTIFICATION_RULES_MAX_SIZE:1000}" # 0 means the cache is disabled rateLimits: timeToLiveInMinutes: "${CACHE_SPECS_RATE_LIMITS_TTL:120}" # Rate limits cache TTL @@ -896,7 +896,7 @@ transport: proxy_enabled: "${MQTT_PROXY_PROTOCOL_ENABLED:false}" # MQTT processing timeout in milliseconds timeout: "${MQTT_TIMEOUT:10000}" - msg_queue_size_per_device_limit: "${MQTT_MSG_QUEUE_SIZE_PER_DEVICE_LIMIT:100}" # messages await in the queue before device connected state. This limit works on low level before TenantProfileLimits mechanism + msg_queue_size_per_device_limit: "${MQTT_MSG_QUEUE_SIZE_PER_DEVICE_LIMIT:100}" # messages await in the queue before the device connected state. This limit works on the low level before TenantProfileLimits mechanism netty: # Netty leak detector level leak_detector_level: "${NETTY_LEAK_DETECTOR_LVL:DISABLED}" @@ -938,7 +938,7 @@ transport: store_file: "${MQTT_SSL_KEY_STORE:mqttserver.jks}" # Password used to access the key store store_password: "${MQTT_SSL_KEY_STORE_PASSWORD:server_ks_password}" - # Optional alias of the private key; If not set, the platform will load the first private key from the keystore; + # Optional alias of the private key. If not set, the platform will load the first private key from the keystore key_alias: "${MQTT_SSL_KEY_ALIAS:}" # Optional password to access the private key. If not set, the platform will attempt to load the private keys that are not protected with the password; key_password: "${MQTT_SSL_KEY_PASSWORD:server_key_password}" @@ -946,7 +946,7 @@ transport: skip_validity_check_for_client_cert: "${MQTT_SSL_SKIP_VALIDITY_CHECK_FOR_CLIENT_CERT:false}" # Local CoAP transport parameters coap: - # Enable/disable coap transport protocol. + # Enable/disable CoAP transport protocol. enabled: "${COAP_ENABLED:true}" # CoAP bind-address bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" @@ -1002,7 +1002,7 @@ transport: dtls_session_report_timeout: "${TB_COAP_X509_DTLS_SESSION_REPORT_TIMEOUT:1800000}" # Local LwM2M transport parameters lwm2m: - # Enable/disable lvm2m transport protocol. + # Enable/disable LwM2M transport protocol. enabled: "${LWM2M_ENABLED:true}" dtls: # RFC7925_RETRANSMISSION_TIMEOUT_IN_MILLISECONDS = 9000 @@ -1050,7 +1050,7 @@ transport: bootstrap: # Enable/disable Bootstrap Server enabled: "${LWM2M_ENABLED_BS:true}" - # Default value in Lwm2mClient after start in mode Bootstrap for the object : name "LWM2M Security" field: "Short Server ID" (deviceProfile: Bootstrap.BOOTSTRAP SERVER.Short ID) + # Default value in LwM2M client after start in mode Bootstrap for the object : name "LWM2M Security" field: "Short Server ID" (deviceProfile: Bootstrap.BOOTSTRAP SERVER.Short ID) id: "${LWM2M_SERVER_ID_BS:111}" # LwM2M bootstrap server bind address. Bind to all interfaces by default bind_address: "${LWM2M_BS_BIND_ADDRESS:0.0.0.0}" @@ -1071,7 +1071,7 @@ transport: pem: # Path to the server certificate file (holds server certificate or certificate chain, may include server private key) cert_file: "${LWM2M_BS_PEM_CERT:lwm2mserver.pem}" - # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file; + # Path to the server certificate private key file. Optional by default. Required if the private key is not present in server certificate file key_file: "${LWM2M_BS_PEM_KEY:lwm2mserver_key.pem}" # Server certificate private key password (optional) key_password: "${LWM2M_BS_PEM_KEY_PASSWORD:server_key_password}" @@ -1229,7 +1229,7 @@ edges: sleep_between_batches: "${EDGES_SLEEP_BETWEEN_BATCHES:10000}" # Number of threads that are used to check DB for edge events scheduler_pool_size: "${EDGES_SCHEDULER_POOL_SIZE:1}" - # Number of threads that used to send downlink messages to edge over gRPC + # Number of threads that are used to send downlink messages to edge over gRPC send_scheduler_pool_size: "${EDGES_SEND_SCHEDULER_POOL_SIZE:1}" # Number of threads that are used to convert edge events from DB into downlink messages and send them for delivery grpc_callback_thread_pool_size: "${EDGES_GRPC_CALLBACK_POOL_SIZE:1}" @@ -1271,10 +1271,10 @@ queue: type: "${TB_QUEUE_TYPE:in-memory}" # in-memory or kafka (Apache Kafka) or aws-sqs (AWS SQS) or pubsub (PubSub) or service-bus (Azure Service Bus) or rabbitmq (RabbitMQ) in_memory: stats: - # For debug lvl + # For debug level print-interval-ms: "${TB_QUEUE_IN_MEMORY_STATS_PRINT_INTERVAL_MS:60000}" kafka: - # Kafka Bootstrap Servers + # Kafka Bootstrap nodes in "host:port" format bootstrap.servers: "${TB_KAFKA_SERVERS:localhost:9092}" ssl: # Enable/Disable SSL Kafka communication @@ -1289,7 +1289,7 @@ queue: keystore.password: "${TB_KAFKA_SSL_KEYSTORE_PASSWORD:}" # The password of the private key in the key store file or the PEM key specified in ‘keystore.key’ key.password: "${TB_KAFKA_SSL_KEY_PASSWORD:}" - # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0,1 and all + # The number of acknowledgments the producer requires the leader to have received before considering a request complete. This controls the durability of records that are sent. The following settings are allowed:0, 1 and all acks: "${TB_KAFKA_ACKS:all}" # Number of retries. Resend any record whose send fails with a potentially transient error retries: "${TB_KAFKA_RETRIES:1}" @@ -1307,9 +1307,9 @@ queue: buffer.memory: "${TB_BUFFER_MEMORY:33554432}" # The multiple copies of data over the multiple brokers of Kafka replication_factor: "${TB_QUEUE_KAFKA_REPLICATION_FACTOR:1}" - # The maximum delay between invocations of poll() when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records + # The maximum delay between invocations of poll() method when using consumer group management. This places an upper bound on the amount of time that the consumer can be idle before fetching more records max_poll_interval_ms: "${TB_QUEUE_KAFKA_MAX_POLL_INTERVAL_MS:300000}" - # The maximum number of records returned in a single call to poll() + # The maximum number of records returned in a single call of poll() method max_poll_records: "${TB_QUEUE_KAFKA_MAX_POLL_RECORDS:8192}" # The maximum amount of data per-partition the server will return. Records are fetched in batches by the consumer max_partition_fetch_bytes: "${TB_QUEUE_KAFKA_MAX_PARTITION_FETCH_BYTES:16777216}" @@ -1371,7 +1371,7 @@ queue: enabled: "${TB_QUEUE_KAFKA_CONSUMER_STATS_ENABLED:true}" # Statistics printing interval for Kafka's consumer-groups stats print-interval-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_MIN_PRINT_INTERVAL_MS:60000}" - # Time to wait for the stats-loading requests to Kafka to finis + # Time to wait for the stats-loading requests to Kafka to finish kafka-response-timeout-ms: "${TB_QUEUE_KAFKA_CONSUMER_STATS_RESPONSE_TIMEOUT_MS:1000}" aws_sqs: # Use the default credentials provider for AWS SQS @@ -1399,7 +1399,6 @@ queue: ota-updates: "${TB_QUEUE_AWS_SQS_OTA_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds version-control: "${TB_QUEUE_AWS_SQS_VC_QUEUE_PROPERTIES:VisibilityTimeout:30;MaximumMessageSize:262144;MessageRetentionPeriod:604800}" - # VisibilityTimeout in seconds;MaximumMessageSize in bytes;MessageRetentionPeriod in seconds pubsub: # Project ID from Google Cloud project_id: "${TB_QUEUE_PUBSUB_PROJECT_ID:YOUR_PROJECT_ID}" @@ -1659,7 +1658,7 @@ vc: # Notification system parameters notification_system: - # Specify thread pool size for Notification System processing notification rules and notification sending. Recommend value < =10 + # Specify thread pool size for Notification System processing notification rules and notification sending. Recommend value <= 10 thread_pool_size: "${TB_NOTIFICATION_SYSTEM_THREAD_POOL_SIZE:10}" rules: # Semicolon-separated deduplication durations (in millis) for trigger types. Format: 'NotificationRuleTriggerType1:123;NotificationRuleTriggerType2:456' From 4700fff7d2cb44de8b2adaa731f4e016a00369ef Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Sat, 14 Oct 2023 13:27:41 +0200 Subject: [PATCH 177/267] tenant publish event fix: tenant_id instead sys_tenant_id to avoid broadcast messages --- .../org/thingsboard/server/dao/tenant/TenantServiceImpl.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) 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 0f1b60ecb5..e10a80af2d 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 @@ -197,7 +197,7 @@ public class TenantServiceImpl extends AbstractCachedEntityService Date: Mon, 16 Oct 2023 13:46:37 +0200 Subject: [PATCH 178/267] TbKafkaProducerTemplate: addAnalyticHeaders - stacktrace level increased from 10 to 20 for TRACE enabled --- .../server/queue/kafka/TbKafkaProducerTemplate.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java index 850f5c08ea..d67d2c4399 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaProducerTemplate.java @@ -85,8 +85,8 @@ public class TbKafkaProducerTemplate implements TbQueuePro if (log.isTraceEnabled()) { try { StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); - int maxlevel = Math.min(stackTrace.length, 10); - for (int i = 2; i < maxlevel; i++) { // ignore two levels: getStackTrace and addAnalyticHeaders + int maxLevel = Math.min(stackTrace.length, 20); + for (int i = 2; i < maxLevel; i++) { // ignore two levels: getStackTrace and addAnalyticHeaders headers.add(new RecordHeader("_stackTrace" + i, stackTrace[i].toString().getBytes(StandardCharsets.UTF_8))); } } catch (Throwable t) { From 8681d2de62fcc9c0809e08118bc948a22ef3c24a Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 16 Oct 2023 15:06:57 +0300 Subject: [PATCH 179/267] DefaultEdgeNotificationService - Increased deadline timeout to 60 seconds --- .../server/service/edge/DefaultEdgeNotificationService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 7f52ebb94b..84e1faa6cb 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 @@ -157,7 +157,7 @@ public class DefaultEdgeNotificationService implements EdgeNotificationService { public void pushNotificationToEdge(TransportProtos.EdgeNotificationMsgProto edgeNotificationMsg, TbCallback callback) { TenantId tenantId = TenantId.fromUUID(new UUID(edgeNotificationMsg.getTenantIdMSB(), edgeNotificationMsg.getTenantIdLSB())); log.debug("[{}] Pushing notification to edge {}", tenantId, edgeNotificationMsg); - final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(10); + final long deadline = System.nanoTime() + TimeUnit.SECONDS.toNanos(60); try { executor.submit(() -> { try { From ee080538a4a78e217507716a3ed0f36a87887536 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Mon, 16 Oct 2023 15:15:25 +0300 Subject: [PATCH 180/267] DefaultNotificationRuleProcessor - submit to notificationExecutor sooner not to block the caller --- .../DefaultNotificationRuleProcessor.java | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java index e9656f2ea6..70ba344b84 100644 --- a/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/notification/rule/DefaultNotificationRuleProcessor.java @@ -77,18 +77,17 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess public void process(NotificationRuleTrigger trigger) { NotificationRuleTriggerType triggerType = trigger.getType(); TenantId tenantId = triggerType.isTenantLevel() ? trigger.getTenantId() : TenantId.SYS_TENANT_ID; - - try { - List enabledRules = notificationRulesCache.getEnabled(tenantId, triggerType); - if (enabledRules.isEmpty()) { - return; - } - if (trigger.deduplicate()) { - enabledRules = new ArrayList<>(enabledRules); - enabledRules.removeIf(rule -> deduplicationService.alreadyProcessed(trigger, rule)); - } - final List rules = enabledRules; - notificationExecutor.submit(() -> { + notificationExecutor.submit(() -> { + try { + List enabledRules = notificationRulesCache.getEnabled(tenantId, triggerType); + if (enabledRules.isEmpty()) { + return; + } + if (trigger.deduplicate()) { + enabledRules = new ArrayList<>(enabledRules); + enabledRules.removeIf(rule -> deduplicationService.alreadyProcessed(trigger, rule)); + } + final List rules = enabledRules; for (NotificationRule rule : rules) { try { processNotificationRule(rule, trigger); @@ -96,10 +95,10 @@ public class DefaultNotificationRuleProcessor implements NotificationRuleProcess log.error("Failed to process notification rule {} for trigger type {} with trigger object {}", rule.getId(), rule.getTriggerType(), trigger, e); } } - }); - } catch (Throwable e) { - log.error("Failed to process notification rules for trigger: {}", trigger, e); - } + } catch (Throwable e) { + log.error("Failed to process notification rules for trigger: {}", trigger, e); + } + }); } private void processNotificationRule(NotificationRule rule, NotificationRuleTrigger trigger) { From ce8eba2137e31a0ba722e21398d065782c9ba523 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 16 Oct 2023 17:39:47 +0300 Subject: [PATCH 181/267] Ability to sort widget types by createdTime --- .../dao/model/sql/AbstractWidgetTypeEntity.java | 2 +- .../dao/model/sql/WidgetTypeInfoEntity.java | 16 ++++++++++++---- .../server/dao/sql/widget/JpaWidgetTypeDao.java | 9 +++++---- .../dao/sql/widget/JpaWidgetTypeDaoTest.java | 13 +++++++------ 4 files changed, 25 insertions(+), 15 deletions(-) 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 08b2ebed77..fa700315d0 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 @@ -31,7 +31,7 @@ import java.util.UUID; @Data @EqualsAndHashCode(callSuper = true) @MappedSuperclass -public abstract class AbstractWidgetTypeEntity extends BaseSqlEntity implements BaseEntity { +public abstract class AbstractWidgetTypeEntity extends BaseSqlEntity { @Column(name = ModelConstants.WIDGET_TYPE_TENANT_ID_PROPERTY) private UUID tenantId; diff --git a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java index fa6fd895cd..47d965a382 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java +++ b/dao/src/main/java/org/thingsboard/server/dao/model/sql/WidgetTypeInfoEntity.java @@ -18,7 +18,6 @@ package org.thingsboard.server.dao.model.sql; import io.hypersistence.utils.hibernate.type.array.StringArrayType; import lombok.Data; import lombok.EqualsAndHashCode; -import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Type; import org.hibernate.annotations.TypeDef; import org.thingsboard.server.common.data.widget.BaseWidgetType; @@ -28,14 +27,23 @@ import org.thingsboard.server.dao.model.ModelConstants; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Table; +import java.util.HashMap; +import java.util.Map; @Data @EqualsAndHashCode(callSuper = true) @Entity -@Immutable @TypeDef(name = "string-array", typeClass = StringArrayType.class) @Table(name = ModelConstants.WIDGET_TYPE_INFO_VIEW_TABLE_NAME) -public final class WidgetTypeInfoEntity extends AbstractWidgetTypeEntity { +public class WidgetTypeInfoEntity extends AbstractWidgetTypeEntity { + + public static final Map SEARCH_COLUMNS_MAP = new HashMap<>(); + + static { + SEARCH_COLUMNS_MAP.put("createdTime", "created_time"); + SEARCH_COLUMNS_MAP.put("tenantId", "tenant_id"); + SEARCH_COLUMNS_MAP.put("widgetType", "widget_type"); + } @Column(name = ModelConstants.WIDGET_TYPE_IMAGE_PROPERTY) private String image; @@ -43,7 +51,7 @@ public final class WidgetTypeInfoEntity extends AbstractWidgetTypeEntity(); WidgetsBundle widgetsBundle = new WidgetsBundle(); @@ -74,6 +74,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { this.widgetsBundle = widgetsBundleDao.save(TenantId.SYS_TENANT_ID, widgetsBundle); for (int i = 0; i < WIDGET_TYPE_COUNT; i++) { + Thread.sleep(2); var widgetType = createAndSaveWidgetType(TenantId.SYS_TENANT_ID, i); widgetTypeList.add(widgetType); widgetTypeDao.saveWidgetsBundleWidget(new WidgetsBundleWidget(this.widgetsBundle.getId(), widgetType.getId(), i)); @@ -112,12 +113,12 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { @Test public void testFindSystemWidgetTypes() { PageData widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.singletonList("static"), - new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("name"))); + new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))); assertEquals(1, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(1)), widgetTypes.getData().get(0)); widgetTypes = widgetTypeDao.findSystemWidgetTypes(TenantId.SYS_TENANT_ID, true, DeprecatedFilter.ALL, Collections.emptyList(), - new PageLink(1024, 0, "hfgfd tag2_2 ghg", new SortOrder("name"))); + new PageLink(1024, 0, "hfgfd tag2_2 ghg", new SortOrder("createdTime"))); assertEquals(1, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(0)); } @@ -130,7 +131,7 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { widgetTypeList.add(widgetType); } PageData widgetTypes = widgetTypeDao.findTenantWidgetTypesByTenantId(tenantId, true, DeprecatedFilter.ALL, null, - new PageLink(10, 0, "", new SortOrder("name"))); + new PageLink(10, 0, "", new SortOrder("createdTime"))); assertEquals(WIDGET_TYPE_COUNT, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(3)), widgetTypes.getData().get(0)); assertEquals(new WidgetTypeInfo(widgetTypeList.get(4)), widgetTypes.getData().get(1)); @@ -140,13 +141,13 @@ public class JpaWidgetTypeDaoTest extends AbstractJpaDaoTest { @Test public void testFindByWidgetTypeInfosByBundleId() { PageData widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(),true, DeprecatedFilter.ALL, Collections.singletonList("latest"), - new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("name"))); + new PageLink(1024, 0, "TYPE_DESCRIPTION", new SortOrder("createdTime"))); assertEquals(2, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0)); assertEquals(new WidgetTypeInfo(widgetTypeList.get(2)), widgetTypes.getData().get(1)); widgetTypes = widgetTypeDao.findWidgetTypesInfosByWidgetsBundleId(TenantId.SYS_TENANT_ID.getId(), widgetsBundle.getUuidId(), true, DeprecatedFilter.ALL, Collections.emptyList(), - new PageLink(1024, 0, "hfgfd TEST_0 ghg", new SortOrder("name"))); + new PageLink(1024, 0, "hfgfd TEST_0 ghg", new SortOrder("createdTime"))); assertEquals(1, widgetTypes.getData().size()); assertEquals(new WidgetTypeInfo(widgetTypeList.get(0)), widgetTypes.getData().get(0)); } From 8c94ec5c5277610c1dd494c75c1c677898885210 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 16 Oct 2023 18:05:12 +0300 Subject: [PATCH 182/267] Edge: do not sync User login actions. Edge: do not save particular edge events in case edge is not activated or disconnected --- .../edge/EdgeEventSourcingListener.java | 42 +++++++++++--- .../edge/rpc/processor/BaseEdgeProcessor.java | 58 +++++++++++++++++++ .../server/edge/AbstractEdgeTest.java | 49 +++++++--------- .../server/edge/DeviceEdgeTest.java | 2 - .../thingsboard/server/edge/UserEdgeTest.java | 8 --- .../dao/eventsourcing/SaveEntityEvent.java | 1 + .../server/dao/user/UserServiceImpl.java | 7 ++- 7 files changed, 119 insertions(+), 48 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java index 43b05094a4..707dbec964 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java @@ -15,6 +15,8 @@ */ package org.thingsboard.server.service.edge; +import com.fasterxml.jackson.databind.node.NullNode; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; @@ -36,6 +38,7 @@ import org.thingsboard.server.dao.eventsourcing.ActionEntityEvent; import org.thingsboard.server.dao.eventsourcing.DeleteEntityEvent; import org.thingsboard.server.dao.eventsourcing.RelationActionEvent; import org.thingsboard.server.dao.eventsourcing.SaveEntityEvent; +import org.thingsboard.server.dao.user.UserServiceImpl; import javax.annotation.PostConstruct; @@ -75,7 +78,7 @@ public class EdgeEventSourcingListener { return; } try { - if (!isValidEdgeEventEntity(event.getEntity())) { + if (!isValidEdgeEventEntity(event.getEntity(), event.getOldEntity())) { return; } log.trace("[{}] SaveEntityEvent called: {}", event.getTenantId(), event); @@ -83,7 +86,7 @@ public class EdgeEventSourcingListener { tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, event.getEntityId(), null, null, action); } catch (Exception e) { - log.error("[{}] failed to process SaveEntityEvent: {}", event.getTenantId(), event); + log.error("[{}] failed to process SaveEntityEvent: {}", event.getTenantId(), event, e); } } @@ -97,7 +100,7 @@ public class EdgeEventSourcingListener { tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(), JacksonUtil.toString(event.getEntity()), null, EdgeEventActionType.DELETED); } catch (Exception e) { - log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event); + log.error("[{}] failed to process DeleteEntityEvent: {}", event.getTenantId(), event, e); } } @@ -111,7 +114,7 @@ public class EdgeEventSourcingListener { tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), event.getEdgeId(), event.getEntityId(), event.getBody(), null, edgeTypeByActionType(event.getActionType())); } catch (Exception e) { - log.error("[{}] failed to process ActionEntityEvent: {}", event.getTenantId(), event); + log.error("[{}] failed to process ActionEntityEvent: {}", event.getTenantId(), event, e); } } @@ -134,11 +137,11 @@ public class EdgeEventSourcingListener { tbClusterService.sendNotificationMsgToEdge(event.getTenantId(), null, null, JacksonUtil.toString(relation), EdgeEventType.RELATION, edgeTypeByActionType(event.getActionType())); } catch (Exception e) { - log.error("[{}] failed to process RelationActionEvent: {}", event.getTenantId(), event); + log.error("[{}] failed to process RelationActionEvent: {}", event.getTenantId(), event, e); } } - private boolean isValidEdgeEventEntity(Object entity) { + private boolean isValidEdgeEventEntity(Object entity, Object oldEntity) { if (entity instanceof OtaPackageInfo) { OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity; return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData(); @@ -147,7 +150,15 @@ public class EdgeEventSourcingListener { return RuleChainType.EDGE.equals(ruleChain.getType()); } else if (entity instanceof User) { User user = (User) entity; - return !Authority.SYS_ADMIN.equals(user.getAuthority()); + if (Authority.SYS_ADMIN.equals(user.getAuthority())) { + return false; + } + if (oldEntity != null) { + User oldUser = (User) oldEntity; + cleanUpUserAdditionalInfo(oldUser); + cleanUpUserAdditionalInfo(user); + return !user.equals(oldUser); + } } else if (entity instanceof AlarmApiCallResult) { AlarmApiCallResult alarmApiCallResult = (AlarmApiCallResult) entity; return alarmApiCallResult.isModified(); @@ -155,4 +166,21 @@ public class EdgeEventSourcingListener { // Default: If the entity doesn't match any of the conditions, consider it as valid. return true; } + + private void cleanUpUserAdditionalInfo(User user) { + // reset FAILED_LOGIN_ATTEMPTS and LAST_LOGIN_TS - edge is not interested in this information + if (user.getAdditionalInfo() instanceof NullNode) { + user.setAdditionalInfo(null); + } + if (user.getAdditionalInfo() instanceof ObjectNode) { + ObjectNode additionalInfo = ((ObjectNode) user.getAdditionalInfo()); + additionalInfo.remove(UserServiceImpl.FAILED_LOGIN_ATTEMPTS); + additionalInfo.remove(UserServiceImpl.LAST_LOGIN_TS); + if (additionalInfo.isEmpty()) { + user.setAdditionalInfo(null); + } else { + user.setAdditionalInfo(additionalInfo); + } + } + } } diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index 328a64efe2..2d86c1e184 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -24,6 +24,7 @@ import org.springframework.context.annotation.Lazy; import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.Dashboard; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.DeviceProfile; import org.thingsboard.server.common.data.EdgeUtils; @@ -46,6 +47,7 @@ import org.thingsboard.server.common.data.id.EntityViewId; import org.thingsboard.server.common.data.id.RuleChainId; 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.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; @@ -110,11 +112,13 @@ import org.thingsboard.server.service.entitiy.TbNotificationEntityService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache; +import org.thingsboard.server.service.state.DefaultDeviceStateService; import org.thingsboard.server.service.state.DeviceStateService; import org.thingsboard.server.service.telemetry.TelemetrySubscriptionService; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -305,6 +309,60 @@ public abstract class BaseEdgeProcessor { EdgeEventActionType action, EntityId entityId, JsonNode body) { + ListenableFuture> future = attributesService.find(tenantId, edgeId, DataConstants.SERVER_SCOPE, DefaultDeviceStateService.ACTIVITY_STATE); + return Futures.transformAsync(future, activeOpt -> { + if (activeOpt.isEmpty()) { + log.trace("Edge is not activated. Skipping event. tenantId [{}], edgeId [{}], type[{}], " + + "action [{}], entityId [{}], body [{}]", + tenantId, edgeId, type, action, entityId, body); + return Futures.immediateFuture(null); + } + if (activeOpt.get().getBooleanValue().isPresent() && activeOpt.get().getBooleanValue().get()) { + return doSaveEdgeEvent(tenantId, edgeId, type, action, entityId, body); + } else { + if (doSaveIfEdgeIsOffline(type, action)) { + return doSaveEdgeEvent(tenantId, edgeId, type, action, entityId, body); + } else { + log.trace("Edge is not active at the moment. Skipping event. tenantId [{}], edgeId [{}], type[{}], " + + "action [{}], entityId [{}], body [{}]", + tenantId, edgeId, type, action, entityId, body); + return Futures.immediateFuture(null); + } + } + }, dbCallbackExecutorService); + } + + private boolean doSaveIfEdgeIsOffline(EdgeEventType type, + EdgeEventActionType action) { + switch (action) { + case TIMESERIES_UPDATED: + case ALARM_ACK: + case ALARM_CLEAR: + case ALARM_ASSIGNED: + case ALARM_UNASSIGNED: + case CREDENTIALS_REQUEST: + return true; + } + switch (type) { + case ALARM: + case RULE_CHAIN: + case RULE_CHAIN_METADATA: + case USER: + case CUSTOMER: + case TENANT: + case TENANT_PROFILE: + case WIDGETS_BUNDLE: + case WIDGET_TYPE: + case ADMIN_SETTINGS: + case OTA_PACKAGE: + case QUEUE: + case RELATION: + return true; + } + return false; + } + + private ListenableFuture doSaveEdgeEvent(TenantId tenantId, EdgeId edgeId, EdgeEventType type, EdgeEventActionType action, EntityId entityId, JsonNode body) { log.debug("Pushing event to edge queue. tenantId [{}], edgeId [{}], type[{}], " + "action [{}], entityId [{}], body [{}]", tenantId, edgeId, type, action, entityId, body); diff --git a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java index 689847416c..43544dd5cf 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AbstractEdgeTest.java @@ -130,7 +130,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { installation(); edgeImitator = new EdgeImitator("localhost", 7070, edge.getRoutingKey(), edge.getSecret()); - edgeImitator.expectMessageAmount(26); + edgeImitator.expectMessageAmount(21); edgeImitator.connect(); requestEdgeRuleChainMetadata(); @@ -163,9 +163,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { @After public void teardownEdgeTest() { try { - edgeImitator.expectMessageAmount(2); loginTenantAdmin(); - Assert.assertTrue(edgeImitator.waitForMessages()); doDelete("/api/edge/" + edge.getId().toString()) .andExpect(status().isOk()); @@ -228,33 +226,33 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { // 1 message from queue fetcher validateQueues(); - // 2 messages - 1 from rule chain fetcher and 1 from rule chain controller + // 1 from rule chain fetcher UUID ruleChainUUID = validateRuleChains(); // 1 from request message validateRuleChainMetadataUpdates(ruleChainUUID); - // 4 messages - 4 messages from fetcher - 2 from system level ('mail', 'mailTemplates') and 2 from admin level ('mail', 'mailTemplates') + // 4 messages + // - 2 from fetcher - system level ('mail', 'mailTemplates') + // - 2 from fetcher - admin level ('mail', 'mailTemplates') validateAdminSettings(); - // 5 messages + // 4 messages // - 1 from default profile fetcher // - 2 from device profile fetcher (default and thermostat) // - 1 from device fetcher - // - 1 from device controller (thermostat) validateDeviceProfiles(); - // 4 messages + // 3 messages // - 1 from default profile fetcher // - 1 message from asset profile fetcher // - 1 message from asset fetcher - // - 1 message from asset controller validateAssetProfiles(); - // 2 messages - 1 from device fetcher and 1 from device controller + // 1 from device fetcher validateDevices(); - // 2 messages - 1 from asset fetcher and 1 from asset controller + // 1 from asset fetcher validateAssets(); // 1 message from public customer fetcher @@ -308,8 +306,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { // default msg device profile from fetcher // thermostat msg from device profile fetcher // thermostat msg from device fetcher - // thermostat msg from creation of device - Assert.assertEquals(5, deviceProfileUpdateMsgList.size()); + Assert.assertEquals(4, deviceProfileUpdateMsgList.size()); Optional thermostatProfileUpdateMsgOpt = deviceProfileUpdateMsgList.stream().filter(dfum -> THERMOSTAT_DEVICE_PROFILE_NAME.equals(dfum.getName())).findAny(); Assert.assertTrue(thermostatProfileUpdateMsgOpt.isPresent()); @@ -326,10 +323,9 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } private void validateDevices() throws Exception { - List deviceUpdateMsgs = edgeImitator.findAllMessagesByType(DeviceUpdateMsg.class); - Assert.assertEquals(2, deviceUpdateMsgs.size()); - validateDevice(deviceUpdateMsgs.get(0)); - validateDevice(deviceUpdateMsgs.get(1)); + Optional deviceUpdateMsgOpt = edgeImitator.findMessageByType(DeviceUpdateMsg.class); + Assert.assertTrue(deviceUpdateMsgOpt.isPresent()); + validateDevice(deviceUpdateMsgOpt.get()); } private void validateDevice(DeviceUpdateMsg deviceUpdateMsg) throws Exception { @@ -345,10 +341,9 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } private void validateAssets() throws Exception { - List assetUpdateMsgs = edgeImitator.findAllMessagesByType(AssetUpdateMsg.class); - Assert.assertEquals(2, assetUpdateMsgs.size()); - validateAsset(assetUpdateMsgs.get(0)); - validateAsset(assetUpdateMsgs.get(1)); + Optional assetUpdateMsgOpt = edgeImitator.findMessageByType(AssetUpdateMsg.class); + Assert.assertTrue(assetUpdateMsgOpt.isPresent()); + validateAsset(assetUpdateMsgOpt.get()); } private void validateAsset(AssetUpdateMsg assetUpdateMsg) throws Exception { @@ -365,12 +360,10 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { } private UUID validateRuleChains() throws Exception { - List ruleChainUpdateMsgs = edgeImitator.findAllMessagesByType(RuleChainUpdateMsg.class); - Assert.assertEquals(2, ruleChainUpdateMsgs.size()); - RuleChainUpdateMsg ruleChainCreateMsg = ruleChainUpdateMsgs.get(0); - RuleChainUpdateMsg ruleChainUpdateMsg = ruleChainUpdateMsgs.get(1); - validateRuleChain(ruleChainCreateMsg, UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); - validateRuleChain(ruleChainUpdateMsg, UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE); + Optional ruleChainUpdateMsgOpt = edgeImitator.findMessageByType(RuleChainUpdateMsg.class); + Assert.assertTrue(ruleChainUpdateMsgOpt.isPresent()); + RuleChainUpdateMsg ruleChainUpdateMsg = ruleChainUpdateMsgOpt.get(); + validateRuleChain(ruleChainUpdateMsg, UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE); return new UUID(ruleChainUpdateMsg.getIdMSB(), ruleChainUpdateMsg.getIdLSB()); } @@ -429,7 +422,7 @@ abstract public class AbstractEdgeTest extends AbstractControllerTest { private void validateAssetProfiles() throws Exception { List assetProfileUpdateMsgs = edgeImitator.findAllMessagesByType(AssetProfileUpdateMsg.class); - Assert.assertEquals(4, assetProfileUpdateMsgs.size()); + Assert.assertEquals(3, assetProfileUpdateMsgs.size()); AssetProfileUpdateMsg assetProfileUpdateMsg = assetProfileUpdateMsgs.get(0); Assert.assertEquals(UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, assetProfileUpdateMsg.getMsgType()); UUID assetProfileUUID = new UUID(assetProfileUpdateMsg.getIdMSB(), assetProfileUpdateMsg.getIdLSB()); diff --git a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java index aed99b4cba..ca8dd5dbf0 100644 --- a/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/DeviceEdgeTest.java @@ -274,9 +274,7 @@ public class DeviceEdgeTest extends AbstractEdgeTest { tenantProfile.getProfileData().setConfiguration(profileConfiguration); doPost("/api/tenantProfile/", tenantProfile, TenantProfile.class); - edgeImitator.expectMessageAmount(2); loginTenantAdmin(); - Assert.assertTrue(edgeImitator.waitForMessages()); UUID uuid = Uuids.timeBased(); diff --git a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java index 3fd39328d5..3dc398b9f3 100644 --- a/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/UserEdgeTest.java @@ -79,9 +79,7 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedTenantAdmin.getLastName(), userUpdateMsg.getLastName()); // update user credentials - edgeImitator.expectMessageAmount(2); login(savedTenantAdmin.getEmail(), "tenant"); - Assert.assertTrue(edgeImitator.waitForMessages()); edgeImitator.expectMessageAmount(1); ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest(); @@ -96,9 +94,7 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedTenantAdmin.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword())); - edgeImitator.expectMessageAmount(2); loginTenantAdmin(); - Assert.assertTrue(edgeImitator.waitForMessages()); // delete user edgeImitator.expectMessageAmount(1); @@ -164,9 +160,7 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedCustomerUser.getLastName(), userUpdateMsg.getLastName()); // update user credentials - edgeImitator.expectMessageAmount(2); login(savedCustomerUser.getEmail(), "customer"); - Assert.assertTrue(edgeImitator.waitForMessages()); edgeImitator.expectMessageAmount(1); ChangePasswordRequest changePasswordRequest = new ChangePasswordRequest(); @@ -181,9 +175,7 @@ public class UserEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedCustomerUser.getUuidId().getLeastSignificantBits(), userCredentialsUpdateMsg.getUserIdLSB()); Assert.assertTrue(passwordEncoder.matches(changePasswordRequest.getNewPassword(), userCredentialsUpdateMsg.getPassword())); - edgeImitator.expectMessageAmount(2); loginTenantAdmin(); - Assert.assertTrue(edgeImitator.waitForMessages()); // delete user edgeImitator.expectMessageAmount(1); diff --git a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java index 205f592d43..cc2e854f59 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java +++ b/dao/src/main/java/org/thingsboard/server/dao/eventsourcing/SaveEntityEvent.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.data.id.TenantId; public class SaveEntityEvent { private final TenantId tenantId; private final T entity; + private final T oldEntity; private final EntityId entityId; private final Boolean added; } 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 4db1eb668a..a584fef86c 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 @@ -70,8 +70,8 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic public static final String USER_PASSWORD_HISTORY = "userPasswordHistory"; - private static final String LAST_LOGIN_TS = "lastLoginTs"; - private static final String FAILED_LOGIN_ATTEMPTS = "failedLoginAttempts"; + public static final String LAST_LOGIN_TS = "lastLoginTs"; + public static final String FAILED_LOGIN_ATTEMPTS = "failedLoginAttempts"; private static final int DEFAULT_TOKEN_LENGTH = 30; public static final String INCORRECT_USER_ID = "Incorrect userId "; @@ -126,7 +126,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic @Override public User saveUser(TenantId tenantId, User user) { log.trace("Executing saveUser [{}]", user); - userValidator.validate(user, User::getTenantId); + User oldUser = userValidator.validate(user, User::getTenantId); if (!userLoginCaseSensitive) { user.setEmail(user.getEmail().toLowerCase()); } @@ -143,6 +143,7 @@ public class UserServiceImpl extends AbstractEntityService implements UserServic eventPublisher.publishEvent(SaveEntityEvent.builder() .tenantId(tenantId == null ? TenantId.SYS_TENANT_ID : tenantId) .entity(savedUser) + .oldEntity(oldUser) .entityId(savedUser.getId()) .added(user.getId() == null).build()); return savedUser; From f97350cd8a97dd2ec1b2309e0142fae8ecbbcf9e Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 17 Oct 2023 10:00:34 +0300 Subject: [PATCH 183/267] UI: Implement 'Simple Value and chart card' widget. --- .../json/system/widget_bundles/cards.json | 1 + .../simple_value_and_chart_card.json | 27 ++ .../basic/basic-widget-config.module.ts | 12 +- ...lue-chart-card-basic-config.component.html | 134 ++++++++++ ...value-chart-card-basic-config.component.ts | 250 ++++++++++++++++++ .../timewindow-config-panel.component.ts | 2 +- .../value-chart-card-widget.component.html | 25 ++ .../value-chart-card-widget.component.scss | 58 ++++ .../value-chart-card-widget.component.ts | 247 +++++++++++++++++ .../cards/value-chart-card-widget.models.ts | 77 ++++++ ...-chart-card-widget-settings.component.html | 54 ++++ ...ue-chart-card-widget-settings.component.ts | 98 +++++++ .../lib/settings/widget-settings.module.ts | 12 +- .../widget/widget-components.module.ts | 7 +- .../assets/locale/locale.constant-en_US.json | 10 + .../widget/value-chart-card/left-layout.svg | 21 ++ .../widget/value-chart-card/right-layout.svg | 30 +++ 17 files changed, 1056 insertions(+), 9 deletions(-) create mode 100644 application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.ts create mode 100644 ui-ngx/src/assets/widget/value-chart-card/left-layout.svg create mode 100644 ui-ngx/src/assets/widget/value-chart-card/right-layout.svg 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 f07f1e858e..d49db3581d 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -11,6 +11,7 @@ "cards.value_card", "cards.horizontal_value_card", "cards.aggregated_value_card", + "simple_value_and_chart_card", "cards.label_widget", "cards.dashboard_state_widget", "cards.qr_code", diff --git a/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json b/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json new file mode 100644 index 0000000000..7fa97f4a52 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json @@ -0,0 +1,27 @@ +{ + "fqn": "simple_value_and_chart_card", + "name": "Simple Value and chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a single entity historical telemetry values as a simplified chart. Optionally may display the corresponding latest telemetry value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"rgb(63, 82, 221)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgb(63, 82, 221)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Simple Value and chart card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"°C\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": null +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index 639ede30f4..fd0e48322d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -64,6 +64,9 @@ import { import { SignalStrengthBasicConfigComponent } from '@home/components/widget/config/basic/indicator/signal-strength-basic-config.component'; +import { + ValueChartCardBasicConfigComponent +} from '@home/components/widget/config/basic/cards/value-chart-card-basic-config.component'; @NgModule({ declarations: [ @@ -83,7 +86,8 @@ import { EntityCountBasicConfigComponent, BatteryLevelBasicConfigComponent, WindSpeedDirectionBasicConfigComponent, - SignalStrengthBasicConfigComponent + SignalStrengthBasicConfigComponent, + ValueChartCardBasicConfigComponent ], imports: [ CommonModule, @@ -107,7 +111,8 @@ import { EntityCountBasicConfigComponent, BatteryLevelBasicConfigComponent, WindSpeedDirectionBasicConfigComponent, - SignalStrengthBasicConfigComponent + SignalStrengthBasicConfigComponent, + ValueChartCardBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -125,5 +130,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + + + +
+
widget-config.appearance
+ + + {{ valueChartCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.value-chart-card.auto-scale' | translate }} + +
+
+ + {{ 'widget-config.title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.value-chart-card.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.value-chart-card.value' | translate }} + +
+ + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+
{{ 'widgets.value-chart-card.chart' | translate }}
+ + +
+
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts new file mode 100644 index 0000000000..f2c3a853a0 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts @@ -0,0 +1,250 @@ +/// +/// Copyright © 2016-2023 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 { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { DataKey, Datasource, WidgetConfig, } from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; +import { formatValue, isUndefined } from '@core/utils'; +import { cssSizeToStrSize, getDataKey, resolveCssSize } from '@shared/models/widget-settings.models'; +import { + valueCartCardLayouts, + valueChartCardDefaultSettings, + valueChartCardLayoutImages, + valueChartCardLayoutTranslations, + ValueChartCardWidgetSettings +} from '@home/components/widget/lib/cards/value-chart-card-widget.models'; + +@Component({ + selector: 'tb-value-chart-card-basic-config', + templateUrl: './value-chart-card-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class ValueChartCardBasicConfigComponent extends BasicWidgetConfigComponent { + + public get datasource(): Datasource { + const datasources: Datasource[] = this.valueChartCardWidgetConfigForm.get('datasources').value; + if (datasources && datasources.length) { + return datasources[0]; + } else { + return null; + } + } + + valueChartCardLayouts = valueCartCardLayouts; + + valueChartCardLayoutTranslationMap = valueChartCardLayoutTranslations; + valueChartCardLayoutImageMap = valueChartCardLayoutImages; + + valueChartCardWidgetConfigForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.valueChartCardWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, [ + { name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, color: 'rgba(63, 82, 221, 1)'} + ], + [{ name: 'temperature', label: 'Latest', type: DataKeyType.timeseries}] + ); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: ValueChartCardWidgetSettings = {...valueChartCardDefaultSettings, ...(configData.config.settings || {})}; + const dataKey = getDataKey(configData.config.datasources); + const iconSize = resolveCssSize(configData.config.iconSize); + this.valueChartCardWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + + layout: [settings.layout, []], + autoScale: [settings.autoScale, []], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + + showIcon: [configData.config.showTitleIcon, []], + iconSize: [iconSize[0], [Validators.min(0)]], + iconSizeUnit: [iconSize[1], []], + icon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + showValue: [settings.showValue, []], + units: [configData.config.units, []], + decimals: [configData.config.decimals, []], + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + chartColor: [dataKey?.color, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showIcon; + this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); + this.widgetConfig.config.titleIcon = config.icon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.layout = config.layout; + this.widgetConfig.config.settings.autoScale = config.autoScale; + + this.widgetConfig.config.settings.showValue = config.showValue; + this.widgetConfig.config.units = config.units; + this.widgetConfig.config.decimals = config.decimals; + this.widgetConfig.config.settings.valueFont = config.valueFont; + this.widgetConfig.config.settings.valueColor = config.valueColor; + + const dataKey = getDataKey(this.widgetConfig.config.datasources); + if (dataKey) { + dataKey.color = config.chartColor; + this.updateLatestValues(dataKey, this.widgetConfig.config.datasources); + } + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showIcon', 'showValue']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.valueChartCardWidgetConfigForm.get('showTitle').value; + const showIcon: boolean = this.valueChartCardWidgetConfigForm.get('showIcon').value; + const showValue: boolean = this.valueChartCardWidgetConfigForm.get('showValue').value; + + if (showTitle) { + this.valueChartCardWidgetConfigForm.get('title').enable(); + this.valueChartCardWidgetConfigForm.get('titleFont').enable(); + this.valueChartCardWidgetConfigForm.get('titleColor').enable(); + this.valueChartCardWidgetConfigForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.valueChartCardWidgetConfigForm.get('iconSize').enable(); + this.valueChartCardWidgetConfigForm.get('iconSizeUnit').enable(); + this.valueChartCardWidgetConfigForm.get('icon').enable(); + this.valueChartCardWidgetConfigForm.get('iconColor').enable(); + } else { + this.valueChartCardWidgetConfigForm.get('iconSize').disable(); + this.valueChartCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.valueChartCardWidgetConfigForm.get('icon').disable(); + this.valueChartCardWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.valueChartCardWidgetConfigForm.get('title').disable(); + this.valueChartCardWidgetConfigForm.get('titleFont').disable(); + this.valueChartCardWidgetConfigForm.get('titleColor').disable(); + this.valueChartCardWidgetConfigForm.get('showIcon').disable({emitEvent: false}); + this.valueChartCardWidgetConfigForm.get('iconSize').disable(); + this.valueChartCardWidgetConfigForm.get('iconSizeUnit').disable(); + this.valueChartCardWidgetConfigForm.get('icon').disable(); + this.valueChartCardWidgetConfigForm.get('iconColor').disable(); + } + + if (showValue) { + this.valueChartCardWidgetConfigForm.get('units').enable(); + this.valueChartCardWidgetConfigForm.get('decimals').enable(); + this.valueChartCardWidgetConfigForm.get('valueFont').enable(); + this.valueChartCardWidgetConfigForm.get('valueColor').enable(); + } else { + this.valueChartCardWidgetConfigForm.get('units').disable(); + this.valueChartCardWidgetConfigForm.get('decimals').disable(); + this.valueChartCardWidgetConfigForm.get('valueFont').disable(); + this.valueChartCardWidgetConfigForm.get('valueColor').disable(); + } + } + + private updateLatestValues(sourceDataKey: DataKey, datasources?: Datasource[]) { + if (datasources && datasources.length) { + let latestDataKeys = datasources[0].latestDataKeys; + if (!latestDataKeys) { + latestDataKeys = []; + datasources[0].latestDataKeys = latestDataKeys; + } + let dataKey: DataKey; + if (!latestDataKeys.length) { + dataKey = {...sourceDataKey}; + latestDataKeys.push(dataKey); + } else { + dataKey = latestDataKeys[0]; + dataKey = {...dataKey, ...sourceDataKey}; + latestDataKeys[0] = dataKey; + } + dataKey.label = 'Latest'; + dataKey.units = null; + dataKey.decimals = null; + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, true); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts index 93fc304b7a..556d6e283c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/timewindow-config-panel.component.ts @@ -92,7 +92,7 @@ export class TimewindowConfigPanelComponent implements ControlValueAccessor, OnI timewindowStyle: [null, []] }); this.timewindowConfig.valueChanges.subscribe( - (val) => this.propagateChange(val) + () => this.propagateChange(this.timewindowConfig.getRawValue()) ); this.timewindowConfig.get('useDashboardTimewindow').valueChanges.subscribe(() => { this.updateTimewindowConfigEnabledState(); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.html new file mode 100644 index 0000000000..b1789800eb --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.html @@ -0,0 +1,25 @@ + +
+
+ +
+
{{ valueText }}
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.scss new file mode 100644 index 0000000000..3ea61fdcec --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.scss @@ -0,0 +1,58 @@ +/** + * Copyright © 2016-2023 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-value-chart-card-panel { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + gap: 8px; + padding: 20px 24px 24px 24px; + > div:not(.tb-value-chart-card-overlay) { + z-index: 1; + } + div.tb-widget-title { + padding: 0; + } + .tb-value-chart-card-overlay { + position: absolute; + top: 12px; + left: 12px; + bottom: 12px; + right: 12px; + } + .tb-value-chart-card-content { + min-height: 0; + flex: 1; + display: flex; + align-items: flex-end; + gap: 16px; + position: relative; + &.left { + flex-direction: row; + } + &.right { + flex-direction: row-reverse; + } + .tb-value-chart-card-value { + white-space: nowrap; + } + .tb-value-chart-card-chart { + flex: 1; + height: 100%; + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts new file mode 100644 index 0000000000..7cd58e3c13 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts @@ -0,0 +1,247 @@ +/// +/// Copyright © 2016-2023 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 { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnDestroy, + OnInit, + Renderer2, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { formatValue, isDefinedAndNotNull } from '@core/utils'; +import { + backgroundStyle, + ColorProcessor, + ComponentStyle, + getDataKey, + overlayStyle, resolveCssSize, + textStyle +} from '@shared/models/widget-settings.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { ResizeObserver } from '@juggle/resize-observer'; +import { + valueChartCardDefaultSettings, + ValueChartCardLayout, + ValueChartCardWidgetSettings +} from '@home/components/widget/lib/cards/value-chart-card-widget.models'; +import { TbFlot } from '@home/components/widget/lib/flot-widget'; +import { DataKey } from '@shared/models/widget.models'; +import { TbFlotKeySettings, TbFlotSettings } from '@home/components/widget/lib/flot-widget.models'; +import { getTsValueByLatestDataKey } from '@home/components/widget/lib/cards/aggregated-value-card.models'; + +const layoutWidth = 218; +const layoutValueWidth = 68; +const valueRelativeWidth = layoutValueWidth / layoutWidth; + +@Component({ + selector: 'tb-value-chart-card-widget', + templateUrl: './value-chart-card-widget.component.html', + styleUrls: ['./value-chart-card-widget.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnDestroy { + + @ViewChild('chartElement', {static: false}) + chartElement: ElementRef; + + @ViewChild('valueChartCardContent', {static: false}) + valueChartCardContent: ElementRef; + + @ViewChild('valueChartCardValue', {static: false}) + valueChartCardValue: ElementRef; + + settings: ValueChartCardWidgetSettings; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + layout: ValueChartCardLayout; + + showValue = true; + valueText = 'N/A'; + valueStyle: ComponentStyle = {}; + valueColor: ColorProcessor; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + private flot: TbFlot; + private flotDataKey: DataKey; + + private valueKey: DataKey; + + private contentResize$: ResizeObserver; + + private decimals = 0; + private units = ''; + + constructor(private renderer: Renderer2, + private widgetComponent: WidgetComponent, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.valueChartCardWidget = this; + this.settings = {...valueChartCardDefaultSettings, ...this.ctx.settings}; + + if (this.showValue) { + this.decimals = this.ctx.decimals; + this.units = this.ctx.units; + const dataKey = getDataKey(this.ctx.datasources); + if (dataKey?.name && this.ctx.defaultSubscription.firstDatasource?.latestDataKeys?.length) { + const dataKeys = this.ctx.defaultSubscription.firstDatasource?.latestDataKeys; + this.valueKey = dataKeys?.find(k => k.name === dataKey.name); + if (isDefinedAndNotNull(this.valueKey?.decimals)) { + this.decimals = this.valueKey.decimals; + } + if (this.valueKey?.units) { + this.units = dataKey.units; + } + } + } + + this.layout = this.settings.layout; + + this.showValue = this.settings.showValue; + this.valueStyle = textStyle(this.settings.valueFont, '0.25px'); + this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); + + this.backgroundStyle = backgroundStyle(this.settings.background); + this.overlayStyle = overlayStyle(this.settings.background.overlay); + + if (this.ctx.defaultSubscription.firstDatasource?.dataKeys?.length) { + this.flotDataKey = this.ctx.defaultSubscription.firstDatasource?.dataKeys[0]; + this.flotDataKey.settings = { + fillLines: false, + showLines: true, + lineWidth: 2 + } as TbFlotKeySettings; + } + } + + public ngAfterViewInit() { + const settings = { + shadowSize: 0, + enableSelection: false, + smoothLines: true, + grid: { + tickColor: 'rgba(0,0,0,0.12)', + horizontalLines: false, + verticalLines: false, + outlineWidth: 0, + minBorderMargin: 0, + margin: 0 + }, + yaxis: { + showLabels: false, + tickGenerator: 'return [(axis.max + axis.min) / 2];' + }, + xaxis: { + showLabels: false + } + } as TbFlotSettings; + this.flot = new TbFlot(this.ctx, 'line', $(this.chartElement.nativeElement), settings); + + this.contentResize$ = new ResizeObserver(() => { + this.onResize(); + }); + this.contentResize$.observe(this.valueChartCardContent.nativeElement); + this.onResize(); + } + + ngOnDestroy() { + if (this.contentResize$) { + this.contentResize$.disconnect(); + } + } + + public onInit() { + const borderRadius = this.ctx.$widgetElement.css('borderRadius'); + this.overlayStyle = {...this.overlayStyle, ...{borderRadius}}; + this.cd.detectChanges(); + } + + public onDataUpdated() { + this.flot.update(); + } + + public onLatestDataUpdated() { + if (this.showValue && this.valueKey) { + const tsValue = getTsValueByLatestDataKey(this.ctx.latestData, this.valueKey); + let value; + if (tsValue) { + value = tsValue[1]; + this.valueText = formatValue(value, this.decimals, this.units, true); + } else { + this.valueText = 'N/A'; + } + this.valueColor.update(value); + this.cd.detectChanges(); + setTimeout(() => { + this.onResize(false); + }, 0); + } + } + + public onEditModeChanged() { + this.flot.checkMouseEvents(); + } + + public onDestroy() { + this.flot.destroy(); + } + + private onResize(fitMaxWidth = true) { + if (this.settings.autoScale && this.showValue) { + const contentWidth = this.valueChartCardContent.nativeElement.getBoundingClientRect().width; + const contentHeight = this.valueChartCardContent.nativeElement.getBoundingClientRect().height; + const targetValueWidth = valueRelativeWidth * contentWidth; + this.setValueFontSize(targetValueWidth, contentHeight, fitMaxWidth); + } + this.flot.resize(); + } + + private setValueFontSize(maxWidth: number, maxHeight: number, fitMaxWidth = true) { + const fontSize = getComputedStyle(this.valueChartCardValue.nativeElement).fontSize; + let valueFontSize = resolveCssSize(fontSize)[0]; + this.renderer.setStyle(this.valueChartCardValue.nativeElement, 'fontSize', valueFontSize + 'px'); + this.renderer.setStyle(this.valueChartCardValue.nativeElement, 'lineHeight', '1'); + let valueWidth = this.valueChartCardValue.nativeElement.getBoundingClientRect().width; + while (fitMaxWidth && valueWidth < maxWidth) { + valueFontSize++; + this.renderer.setStyle(this.valueChartCardValue.nativeElement, 'fontSize', valueFontSize + 'px'); + valueWidth = this.valueChartCardValue.nativeElement.getBoundingClientRect().width; + } + let valueHeight = this.valueChartCardValue.nativeElement.getBoundingClientRect().height; + while ((valueWidth > maxWidth || valueHeight > maxHeight) && valueFontSize > 6) { + valueFontSize--; + this.renderer.setStyle(this.valueChartCardValue.nativeElement, 'fontSize', valueFontSize + 'px'); + valueWidth = this.valueChartCardValue.nativeElement.getBoundingClientRect().width; + valueHeight = this.valueChartCardValue.nativeElement.getBoundingClientRect().height; + } + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.models.ts new file mode 100644 index 0000000000..e7a4a6d356 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.models.ts @@ -0,0 +1,77 @@ +/// +/// Copyright © 2016-2023 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 { + BackgroundSettings, + BackgroundType, + ColorSettings, + constantColor, + Font +} from '@shared/models/widget-settings.models'; + +export enum ValueChartCardLayout { + left = 'left', + right = 'right' +} + +export const valueCartCardLayouts = Object.keys(ValueChartCardLayout) as ValueChartCardLayout[]; + +export const valueChartCardLayoutTranslations = new Map( + [ + [ValueChartCardLayout.left, 'widgets.value-chart-card.layout-left'], + [ValueChartCardLayout.right, 'widgets.value-chart-card.layout-right'] + ] +); + +export const valueChartCardLayoutImages = new Map( + [ + [ValueChartCardLayout.left, 'assets/widget/value-chart-card/left-layout.svg'], + [ValueChartCardLayout.right, 'assets/widget/value-chart-card/right-layout.svg'] + ] +); + +export interface ValueChartCardWidgetSettings { + layout: ValueChartCardLayout; + autoScale: boolean; + showValue: boolean; + valueFont: Font; + valueColor: ColorSettings; + background: BackgroundSettings; +} + +export const valueChartCardDefaultSettings: ValueChartCardWidgetSettings = { + layout: ValueChartCardLayout.left, + autoScale: true, + showValue: true, + valueFont: { + family: 'Roboto', + size: 28, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '32px' + }, + valueColor: constantColor('rgba(0, 0, 0, 0.87)'), + background: { + type: BackgroundType.color, + color: '#fff', + overlay: { + enabled: false, + color: 'rgba(255,255,255,0.72)', + blur: 3 + } + } +}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.html new file mode 100644 index 0000000000..5b4a671772 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.html @@ -0,0 +1,54 @@ + + +
+
widgets.value-chart-card.value-chart-card-style
+ + + {{ valueChartCardLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.value-chart-card.auto-scale' | translate }} + +
+
+ + {{ 'widgets.value-chart-card.value' | translate }} + +
+ + + + +
+
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.ts new file mode 100644 index 0000000000..88db47b3ad --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component.ts @@ -0,0 +1,98 @@ +/// +/// Copyright © 2016-2023 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, Injector } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue } from '@core/utils'; +import { + valueCartCardLayouts, + valueChartCardDefaultSettings, + valueChartCardLayoutImages, + valueChartCardLayoutTranslations +} from '@home/components/widget/lib/cards/value-chart-card-widget.models'; + +@Component({ + selector: 'tb-value-chart-card-widget-settings', + templateUrl: './value-chart-card-widget-settings.component.html', + styleUrls: [] +}) +export class ValueChartCardWidgetSettingsComponent extends WidgetSettingsComponent { + + valueChartCardLayouts = valueCartCardLayouts; + + valueChartCardLayoutTranslationMap = valueChartCardLayoutTranslations; + valueChartCardLayoutImageMap = valueChartCardLayoutImages; + + valueChartCardWidgetSettingsForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.valueChartCardWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...valueChartCardDefaultSettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.valueChartCardWidgetSettingsForm = this.fb.group({ + layout: [settings.layout, []], + autoScale: [settings.autoScale, []], + + showValue: [settings.showValue, []], + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showValue']; + } + + protected updateValidators(emitEvent: boolean) { + const showValue: boolean = this.valueChartCardWidgetSettingsForm.get('showValue').value; + + if (showValue) { + this.valueChartCardWidgetSettingsForm.get('valueFont').enable(); + this.valueChartCardWidgetSettingsForm.get('valueColor').enable(); + } else { + this.valueChartCardWidgetSettingsForm.get('valueFont').disable(); + this.valueChartCardWidgetSettingsForm.get('valueColor').disable(); + } + + this.valueChartCardWidgetSettingsForm.get('valueFont').updateValueAndValidity({emitEvent}); + this.valueChartCardWidgetSettingsForm.get('valueColor').updateValueAndValidity({emitEvent}); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(22, decimals, units, true); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index 595b2bdc41..c4d2a1edc5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -294,6 +294,9 @@ import { import { SignalStrengthWidgetSettingsComponent } from '@home/components/widget/lib/settings/indicator/signal-strength-widget-settings.component'; +import { + ValueChartCardWidgetSettingsComponent +} from '@home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component'; @NgModule({ declarations: [ @@ -402,7 +405,8 @@ import { EntityCountWidgetSettingsComponent, BatteryLevelWidgetSettingsComponent, WindSpeedDirectionWidgetSettingsComponent, - SignalStrengthWidgetSettingsComponent + SignalStrengthWidgetSettingsComponent, + ValueChartCardWidgetSettingsComponent ], imports: [ CommonModule, @@ -516,7 +520,8 @@ import { EntityCountWidgetSettingsComponent, BatteryLevelWidgetSettingsComponent, WindSpeedDirectionWidgetSettingsComponent, - SignalStrengthWidgetSettingsComponent + SignalStrengthWidgetSettingsComponent, + ValueChartCardWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -595,5 +600,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/value-chart-card/right-layout.svg b/ui-ngx/src/assets/widget/value-chart-card/right-layout.svg new file mode 100644 index 0000000000..662b62d47a --- /dev/null +++ b/ui-ngx/src/assets/widget/value-chart-card/right-layout.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f03751366b7686b337d25f5bcb1e53a3eeceee7f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 17 Oct 2023 10:29:57 +0300 Subject: [PATCH 184/267] UI: Added breadcrumbs when navigate to editing widgets from the widget bundle --- .../widget/widget-library-routing.module.ts | 159 ++++++++---------- .../widgets-bundle-widgets.component.ts | 2 +- 2 files changed, 75 insertions(+), 86 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts index 4c3c933f82..8519b9d4d0 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-library-routing.module.ts @@ -14,14 +14,13 @@ /// limitations under the License. /// -import { Injectable, NgModule } from '@angular/core'; -import { ActivatedRouteSnapshot, Resolve, RouterModule, Routes } from '@angular/router'; +import { inject, NgModule } from '@angular/core'; +import { ActivatedRouteSnapshot, ResolveFn, RouterModule, Routes } from '@angular/router'; import { EntitiesTableComponent } from '../../components/entity/entities-table.component'; import { Authority } from '@shared/models/authority.enum'; import { WidgetsBundlesTableConfigResolver } from '@modules/home/pages/widget/widgets-bundles-table-config.resolver'; import { BreadCrumbConfig, BreadCrumbLabelFunction } from '@shared/components/breadcrumb'; -import { Observable } from 'rxjs'; import { WidgetsBundle } from '@shared/models/widgets-bundle.model'; import { WidgetService } from '@core/http/widget.service'; import { WidgetEditorComponent } from '@home/pages/widget/widget-editor.component'; @@ -38,64 +37,43 @@ export interface WidgetEditorData { widget: WidgetInfo; } -@Injectable() -export class WidgetsBundleResolver implements Resolve { +const widgetsBundleResolver: ResolveFn = (route: ActivatedRouteSnapshot) => { + const widgetsBundleId = route.params.widgetsBundleId; + return inject(WidgetService).getWidgetsBundle(widgetsBundleId); +}; - constructor(private widgetsService: WidgetService) { - } - - resolve(route: ActivatedRouteSnapshot): Observable { - const widgetsBundleId = route.params.widgetsBundleId; - return this.widgetsService.getWidgetsBundle(widgetsBundleId); - } -} - -@Injectable() -export class WidgetsBundleWidgetsResolver implements Resolve> { - - constructor(private widgetsService: WidgetService) { - } - - resolve(route: ActivatedRouteSnapshot): Observable> { - const widgetsBundleId = route.params.widgetsBundleId; - return this.widgetsService.getBundleWidgetTypeInfosList(widgetsBundleId); - } -} - -@Injectable() -export class WidgetEditorDataResolver implements Resolve { +const widgetsBundleWidgetsResolver: ResolveFn> = (route: ActivatedRouteSnapshot) => { + const widgetsBundleId = route.params.widgetsBundleId; + return inject(WidgetService).getBundleWidgetTypeInfosList(widgetsBundleId); +}; - constructor(private widgetsService: WidgetService) { - } - - resolve(route: ActivatedRouteSnapshot): Observable { - const widgetTypeId = route.params.widgetTypeId; - if (!widgetTypeId || Object.keys(widgetType).includes(widgetTypeId)) { - let widgetTypeParam = widgetTypeId as widgetType; - if (!widgetTypeParam) { - widgetTypeParam = widgetType.timeseries; - } - return this.widgetsService.getWidgetTemplate(widgetTypeParam).pipe( - map((widget) => { - widget.widgetName = null; - return { - widgetTypeDetails: null, - widget - }; - }) - ); - } else { - return this.widgetsService.getWidgetTypeById(widgetTypeId).pipe( - map((result) => ({ - widgetTypeDetails: result, - widget: detailsToWidgetInfo(result) - })) - ); +const widgetEditorDataResolver: ResolveFn = (route: ActivatedRouteSnapshot) => { + const widgetTypeId = route.params.widgetTypeId; + if (!widgetTypeId || Object.keys(widgetType).includes(widgetTypeId)) { + let widgetTypeParam = widgetTypeId as widgetType; + if (!widgetTypeParam) { + widgetTypeParam = widgetType.timeseries; } + return inject(WidgetService).getWidgetTemplate(widgetTypeParam).pipe( + map((widget) => { + widget.widgetName = null; + return { + widgetTypeDetails: null, + widget + }; + }) + ); + } else { + return inject(WidgetService).getWidgetTypeById(widgetTypeId).pipe( + map((result) => ({ + widgetTypeDetails: result, + widget: detailsToWidgetInfo(result) + })) + ); } -} +}; -export const widgetsBundleWidgetsBreadcumbLabelFunction: BreadCrumbLabelFunction = ((route, translate) => +export const widgetsBundleWidgetsBreadcumbLabelFunction: BreadCrumbLabelFunction = ((route) => route.data.widgetsBundle.title); export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction = @@ -103,6 +81,26 @@ export const widgetEditorBreadcumbLabelFunction: BreadCrumbLabelFunction, + hideTabs: true + }, + resolve: { + widgetEditorData: widgetEditorDataResolver + } + } +]; + const widgetTypesRoutes: Routes = [ { path: 'widget-types', @@ -124,23 +122,7 @@ const widgetTypesRoutes: Routes = [ entitiesTableConfig: WidgetTypesTableConfigResolver } }, - { - path: ':widgetTypeId', - component: WidgetEditorComponent, - canDeactivate: [ConfirmOnExitGuard], - data: { - auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'widget.editor', - breadcrumb: { - labelFunction: widgetEditorBreadcumbLabelFunction, - icon: 'insert_chart' - } as BreadCrumbConfig, - hideTabs: true - }, - resolve: { - widgetEditorData: WidgetEditorDataResolver - } - } + ...widgetEditorRouter ] }, ]; @@ -168,21 +150,31 @@ const widgetsBundlesRoutes: Routes = [ }, { path: ':widgetsBundleId', - component: WidgetsBundleWidgetsComponent, - canDeactivate: [ConfirmOnExitGuard], data: { - auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], - title: 'widgets-bundle.widgets-bundle-widgets', breadcrumb: { labelFunction: widgetsBundleWidgetsBreadcumbLabelFunction, icon: 'now_widgets' } as BreadCrumbConfig, - hideTabs: true }, resolve: { - widgetsBundle: WidgetsBundleResolver, - widgets: WidgetsBundleWidgetsResolver - } + widgetsBundle: widgetsBundleResolver + }, + children: [ + { + path: '', + component: WidgetsBundleWidgetsComponent, + canDeactivate: [ConfirmOnExitGuard], + data: { + auth: [Authority.SYS_ADMIN, Authority.TENANT_ADMIN], + title: 'widgets-bundle.widgets-bundle-widgets', + hideTabs: true + }, + resolve: { + widgets: widgetsBundleWidgetsResolver + } + }, + ...widgetEditorRouter + ] } ] }, @@ -261,10 +253,7 @@ const routes: Routes = [ exports: [RouterModule], providers: [ WidgetTypesTableConfigResolver, - WidgetsBundlesTableConfigResolver, - WidgetsBundleResolver, - WidgetsBundleWidgetsResolver, - WidgetEditorDataResolver + WidgetsBundlesTableConfigResolver ] }) export class WidgetLibraryRoutingModule { } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts index 58403ad9b2..77d7cb6c2e 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.ts @@ -119,7 +119,7 @@ export class WidgetsBundleWidgetsComponent extends PageComponent implements OnIn if ($event) { $event.stopPropagation(); } - this.router.navigateByUrl(`resources/widgets-library/widget-types/${widgetType.id.id}`); + this.router.navigate([widgetType.id.id], {relativeTo: this.route}).then(()=> {}); } exportWidgetType($event: Event, widgetType: WidgetTypeInfo) { From 9d19a15413cc2ec629aaed4d8ab6fef81542595d Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 Oct 2023 15:12:48 +0200 Subject: [PATCH 185/267] used bouncycastle for parsing cert pem credentials --- .../credentials/CertPemCredentials.java | 302 +++++------------- .../credentials/CertPemCredentialsTest.java | 28 ++ .../src/test/resources/pem/ec_key.pem | 8 + .../test/resources/pem/rsa_encrypted_key.pem | 30 ++ .../pem/rsa_encrypted_traditional_key.pem | 30 ++ .../src/test/resources/pem/rsa_key.pem | 52 +++ 6 files changed, 226 insertions(+), 224 deletions(-) create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index 0137887aaf..c17f71bc33 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -20,68 +20,57 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.codec.binary.Base64; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.bouncycastle.openssl.PEMDecryptorProvider; import org.bouncycastle.openssl.PEMEncryptedKeyPair; import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; -import org.bouncycastle.util.encoders.Hex; +import org.bouncycastle.operator.InputDecryptorProvider; +import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.pkcs.PKCSException; +import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; import org.thingsboard.server.common.data.StringUtils; -import javax.crypto.Cipher; -import javax.crypto.EncryptedPrivateKeyInfo; -import javax.crypto.SecretKey; -import javax.crypto.SecretKeyFactory; -import javax.crypto.spec.IvParameterSpec; -import javax.crypto.spec.PBEKeySpec; -import javax.crypto.spec.SecretKeySpec; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; -import java.io.ByteArrayInputStream; -import java.io.InputStream; -import java.math.BigInteger; -import java.nio.ByteBuffer; -import java.security.AlgorithmParameters; -import java.security.Key; -import java.security.KeyFactory; -import java.security.KeyPair; +import java.io.IOException; +import java.io.StringReader; +import java.security.GeneralSecurityException; import java.security.KeyStore; -import java.security.MessageDigest; import java.security.PrivateKey; import java.security.Security; +import java.security.cert.CertPath; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.security.spec.KeySpec; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.RSAPrivateCrtKeySpec; import java.util.ArrayList; -import java.util.Collections; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import java.util.stream.Collectors; @Data @Slf4j @JsonIgnoreProperties(ignoreUnknown = true) public class CertPemCredentials implements ClientCredentials { - private static final String TLS_VERSION = "TLSv1.2"; + public static final String PRIVATE_KEY_ALIAS = "private-key"; + public static final String X_509 = "X.509"; + public static final String CERT_ALIAS_PREFIX = "cert-"; + public static final String CA_CERT_CERT_ALIAS_PREFIX = "caCert-cert-"; protected String caCert; private String cert; private String privateKey; private String password; - static final String OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX = "\\s*" - + "-----BEGIN RSA PRIVATE KEY-----" + "\\s*" - + "Proc-Type: 4,ENCRYPTED" + "\\s*" - + "DEK-Info:" + "\\s*([^\\s]+)" + "\\s+" - + "([\\s\\S]*)" - + "-----END RSA PRIVATE KEY-----" + "\\s*"; - - static final Pattern OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN = Pattern.compile(OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_REGEX); + public CertPemCredentials() { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(new BouncyCastleProvider()); + } + } @Override public CredentialsType getType() { @@ -91,7 +80,6 @@ public class CertPemCredentials implements ClientCredentials { @Override public SslContext initSslContext() { try { - Security.addProvider(new BouncyCastleProvider()); SslContextBuilder builder = SslContextBuilder.forClient(); if (StringUtils.hasLength(caCert)) { builder.trustManager(createAndInitTrustManagerFactory()); @@ -106,51 +94,13 @@ public class CertPemCredentials implements ClientCredentials { } } - private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { - List certHolders = readCertFile(cert); - Object keyObject = readPrivateKeyFile(privateKey); - char[] passwordCharArray = "".toCharArray(); - if (!StringUtils.isEmpty(password)) { - passwordCharArray = password.toCharArray(); - } - - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter().setProvider("BC"); - - PrivateKey privateKey; - if (keyObject instanceof PEMEncryptedKeyPair) { - PEMDecryptorProvider provider = new JcePEMDecryptorProviderBuilder().build(passwordCharArray); - KeyPair key = keyConverter.getKeyPair(((PEMEncryptedKeyPair) keyObject).decryptKeyPair(provider)); - privateKey = key.getPrivate(); - } else if (keyObject instanceof PEMKeyPair) { - KeyPair key = keyConverter.getKeyPair((PEMKeyPair) keyObject); - privateKey = key.getPrivate(); - } else if (keyObject instanceof PrivateKey) { - privateKey = (PrivateKey) keyObject; - } else { - throw new RuntimeException("Unable to get private key from object: " + keyObject.getClass()); - } - - KeyStore clientKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); - clientKeyStore.load(null, null); - for (X509Certificate certHolder : certHolders) { - clientKeyStore.setCertificateEntry("cert-" + certHolder.getSubjectDN().getName(), certHolder); - } - clientKeyStore.setKeyEntry("private-key", - privateKey, - passwordCharArray, - certHolders.toArray(new Certificate[]{})); - KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); - keyManagerFactory.init(clientKeyStore, passwordCharArray); - return keyManagerFactory; - } - protected TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { - List caCertHolders = readCertFile(caCert); + List caCerts = readCertFile(caCert); KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); caKeyStore.load(null, null); - for (X509Certificate caCertHolder : caCertHolders) { - caKeyStore.setCertificateEntry("caCert-cert-" + caCertHolder.getSubjectDN().getName(), caCertHolder); + for (X509Certificate caCert : caCerts) { + caKeyStore.setCertificateEntry(CA_CERT_CERT_ALIAS_PREFIX + caCert.getSubjectDN().getName(), caCert); } TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); @@ -158,170 +108,74 @@ public class CertPemCredentials implements ClientCredentials { return trustManagerFactory; } - List readCertFile(String fileContent) throws Exception { - if (fileContent == null || fileContent.trim().isEmpty()) { - return Collections.emptyList(); + protected KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { + KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); + kmf.init(loadKeyStore(), password.toCharArray()); + return kmf; + } + + private KeyStore loadKeyStore() throws Exception { + List certificates = readCertFile(this.cert); + PrivateKey privateKey = readPrivateKey(this.privateKey, this.password); + + KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); + keyStore.load(null); + List unique = certificates.stream().distinct().collect(Collectors.toList()); + for (X509Certificate cert : unique) { + keyStore.setCertificateEntry(CERT_ALIAS_PREFIX + cert.getSubjectDN().getName(), cert); } + if (privateKey != null) { + CertificateFactory factory = CertificateFactory.getInstance(X_509); + CertPath certPath = factory.generateCertPath(certificates); + List path = certPath.getCertificates(); + Certificate[] x509Certificates = path.toArray(new Certificate[0]); + keyStore.setKeyEntry(PRIVATE_KEY_ALIAS, privateKey, password.toCharArray(), x509Certificates); + } + return keyStore; + } + + protected List readCertFile(String fileContent) throws IOException, GeneralSecurityException { List certificates = new ArrayList<>(); - String[] pems = fileContent.trim().split("-----END CERTIFICATE-----"); - for (String pem : pems) { - if (pem.trim().isEmpty()) { - continue; - } - pem = pem.replace("-----BEGIN CERTIFICATE-----", "") - .replace("-----END CERTIFICATE-----", "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.decodeBase64(pem); - CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); - try (InputStream inStream = new ByteArrayInputStream(decoded)) { - certificates.add((X509Certificate) certFactory.generateCertificate(inStream)); + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof X509CertificateHolder) { + X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object); + certificates.add(x509Cert); + } } } return certificates; } - private PrivateKey readPrivateKeyFile(String fileContent) throws Exception { + protected PrivateKey readPrivateKey(String fileContent, String password) throws IOException, PKCSException { PrivateKey privateKey = null; - if (fileContent != null && !fileContent.isEmpty()) { - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - KeySpec keySpec = getKeySpec(fileContent); - privateKey = keyFactory.generatePrivate(keySpec); - } - return privateKey; - } - - private KeySpec getKeySpec(String encodedKey) throws Exception { - KeySpec keySpec = null; - Matcher matcher = OPENSSL_ENCRYPTED_RSA_PRIVATEKEY_PATTERN.matcher(encodedKey); - if (matcher.matches()) { - String encryptionDetails = matcher.group(1).trim(); - String encryptedKey = matcher.group(2).replaceAll("\\s", ""); - byte[] encryptedBinaryKey = java.util.Base64.getDecoder().decode(encryptedKey); - String[] encryptionDetailsParts = encryptionDetails.split(","); - if (encryptionDetailsParts.length == 2) { - String encryptionAlgorithm = encryptionDetailsParts[0]; - String encryptedAlgorithmParams = encryptionDetailsParts[1]; - byte[] pw = password.getBytes(); - byte[] iv = Hex.decode(encryptedAlgorithmParams); - - MessageDigest digest = MessageDigest.getInstance("MD5"); - digest.update(pw); - digest.update(iv, 0, 8); - - byte[] round1Digest = digest.digest(); - digest.update(round1Digest); - digest.update(pw); - digest.update(iv, 0, 8); - - byte[] round2Digest = digest.digest(); - Cipher cipher = null; - SecretKey secretKey = null; - byte[] key = null; - - switch(encryptionAlgorithm) { - case "AES-256-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[32]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 16); - secretKey = new SecretKeySpec(key, "AES"); - break; - case "AES-192-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[24]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 8); - secretKey = new SecretKeySpec(key, "AES"); + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + + if (StringUtils.isNotEmpty(fileContent)) { + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray()); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); break; - case "AES-128-CBC": - cipher = Cipher.getInstance("AES/CBC/PKCS5Padding"); - key = new byte[16]; - System.arraycopy(round1Digest, 0, key, 0, 16); - secretKey = new SecretKeySpec(key, "AES"); + } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { + InputDecryptorProvider decProv = + new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(new BouncyCastleProvider()).build(password.toCharArray()); + privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); break; - case "DES-EDE3-CBC": - cipher = Cipher.getInstance("DESede/CBC/PKCS5Padding"); - key = new byte[24]; - System.arraycopy(round1Digest, 0, key, 0, 16); - System.arraycopy(round2Digest, 0, key, 16, 8); - secretKey = new SecretKeySpec(key, "DESede"); - break; - case "DES-CBC": - cipher = Cipher.getInstance("DES/CBC/PKCS5Padding"); - key = new byte[8]; - System.arraycopy(round1Digest, 0, key, 0, 8); - secretKey = new SecretKeySpec(key, "DES"); + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); break; + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); } - if (cipher != null) { - cipher.init(Cipher.DECRYPT_MODE, secretKey, new IvParameterSpec(iv)); - byte[] pkcs1 = cipher.doFinal(encryptedBinaryKey); - keySpec = decodeRSAPrivatePKCS1(pkcs1); - } else { - throw new RuntimeException("Unknown Encryption algorithm!"); } - } else { - throw new RuntimeException("Wrong encryption details!"); } - } else { - encodedKey = encodedKey.replaceAll(".*BEGIN.*PRIVATE KEY.*", "") - .replaceAll(".*END.*PRIVATE KEY.*", "") - .replaceAll("\\s", ""); - byte[] decoded = Base64.decodeBase64(encodedKey); - if (password == null || password.isEmpty()) { - keySpec = new PKCS8EncodedKeySpec(decoded); - } else { - PBEKeySpec pbeKeySpec = new PBEKeySpec(password.toCharArray()); - - EncryptedPrivateKeyInfo privateKeyInfo = new EncryptedPrivateKeyInfo(decoded); - String algorithmName = privateKeyInfo.getAlgName(); - Cipher cipher = Cipher.getInstance(algorithmName); - SecretKeyFactory secretKeyFactory = SecretKeyFactory.getInstance(algorithmName); - - Key pbeKey = secretKeyFactory.generateSecret(pbeKeySpec); - AlgorithmParameters algParams = privateKeyInfo.getAlgParameters(); - cipher.init(Cipher.DECRYPT_MODE, pbeKey, algParams); - keySpec = privateKeyInfo.getKeySpec(cipher); - } - } - return keySpec; - } - - private static BigInteger derint(ByteBuffer input) { - int len = der(input, 0x02); - byte[] value = new byte[len]; - input.get(value); - return new BigInteger(+1, value); - } - - private static int der(ByteBuffer input, int exp) { - int tag = input.get() & 0xFF; - if (tag != exp) throw new IllegalArgumentException("Unexpected tag"); - int n = input.get() & 0xFF; - if (n < 128) return n; - n &= 0x7F; - if ((n < 1) || (n > 2)) throw new IllegalArgumentException("Invalid length"); - int len = 0; - while (n-- > 0) { - len <<= 8; - len |= input.get() & 0xFF; } - return len; - } - - static RSAPrivateCrtKeySpec decodeRSAPrivatePKCS1(byte[] encoded) { - ByteBuffer input = ByteBuffer.wrap(encoded); - if (der(input, 0x30) != input.remaining()) throw new IllegalArgumentException("Excess data"); - if (!BigInteger.ZERO.equals(derint(input))) throw new IllegalArgumentException("Unsupported version"); - BigInteger n = derint(input); - BigInteger e = derint(input); - BigInteger d = derint(input); - BigInteger p = derint(input); - BigInteger q = derint(input); - BigInteger ep = derint(input); - BigInteger eq = derint(input); - BigInteger c = derint(input); - return new RSAPrivateCrtKeySpec(n, e, d, p, q, ep, eq, c); + return privateKey; } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java index 904f470001..fd7f0d3378 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java @@ -18,16 +18,27 @@ package org.thingsboard.rule.engine.credentials; import org.apache.commons.io.FileUtils; import org.junit.Assert; import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; import java.io.File; import java.io.IOException; +import java.security.PrivateKey; import java.security.cert.X509Certificate; import java.util.List; +import java.util.stream.Stream; public class CertPemCredentialsTest { private final CertPemCredentials credentials = new CertPemCredentials(); + private static final String PASS = "test"; + private static final String EMPTY_PASS = ""; + private static final String RSA = "RSA"; + private static final String ECDSA = "ECDSA"; + @Test public void testChainOfCertificates() throws Exception { String fileContent = fileContent("pem/tb-cloud-chain.pem"); @@ -65,6 +76,23 @@ public class CertPemCredentialsTest { Assert.assertEquals(0, x509Certificates.size()); } + private static Stream testReadPrivateKey() { + return Stream.of( + Arguments.of("pem/rsa_key.pem", EMPTY_PASS, RSA), + Arguments.of("pem/rsa_encrypted_key.pem", PASS, RSA), + Arguments.of("pem/rsa_encrypted_traditional_key.pem", PASS, RSA), + Arguments.of("pem/ec_key.pem", EMPTY_PASS, ECDSA) + ); + } + + @ParameterizedTest + @MethodSource + public void testReadPrivateKey(String keyPath, String password, String algorithm) throws Exception { + PrivateKey privateKey = credentials.readPrivateKey(fileContent(keyPath), password); + Assertions.assertNotNull(privateKey); + Assertions.assertEquals(algorithm, privateKey.getAlgorithm()); + } + private String fileContent(String fileName) throws IOException { ClassLoader classLoader = getClass().getClassLoader(); File file = new File(classLoader.getResource(fileName).getFile()); diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem new file mode 100644 index 0000000000..74e0716259 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/ec_key.pem @@ -0,0 +1,8 @@ +-----BEGIN EC PARAMETERS----- +BggqhkjOPQMBBw== +-----END EC PARAMETERS----- +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIIEd0mMh0EEy3fMbOpbUY6kW0oAYcaYoTvoVpZxDr5qZoAoGCCqGSM49 +AwEHoUQDQgAEz4MgawieJfVc5zUOPiw5WFxfHGJf7dOMsHvudDxdOs27PXPbJfi0 +9BVJ3+JjNxA2wQz9KUk877oWRYrN/e+MbA== +-----END EC PRIVATE KEY----- \ No newline at end of file diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem new file mode 100644 index 0000000000..045a44ce28 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_key.pem @@ -0,0 +1,30 @@ +-----BEGIN ENCRYPTED PRIVATE KEY----- +MIIFLTBXBgkqhkiG9w0BBQ0wSjApBgkqhkiG9w0BBQwwHAQILTHGLs8mGUkCAggA +MAwGCCqGSIb3DQIJBQAwHQYJYIZIAWUDBAEqBBAUnb+mChJ9Wu9F7q6ingLYBIIE +0Mwe8Zl6fs5kiT1AL7gXrSSXmyOVvxDFt0V3TX1w399VIadcUUO0RQeEqXoMEUzl +5at99Xmoo7ByvZSPWCdV4d/j5Yw+Z15euxzclSZJnmBgvQx8cFPLCTTaqlgv5r/Y +lTzBrczbgruMFKtzkvHgvZYiagccOtFHDNC1fUBcUR8dkOOsgTiy4QCVo5kkXHt/ +rblE/uVWI8/E318WZBZaz68HcmGIG6ivdMEsKskSKrH6zA3eLjyGB+zSAIPRB/Mp +s7Rj+RK74zFSYyaq6fgdTG8lug2f3rHImSOtQThcfme5XL4P66rUgJsh/sml1vqH +e848VArGoVy3wfvkss6CyXIJevhFh2xVWRyVqG1nraw2QssEnVqIZvdAnaJJONX8 +r1trjHkZ1JD0nO9Mns1c/bw6hjK6W3UwGfgEMM9VQ7wNI2B6CFOXHKTHg6r3us4k +UqaQtfbpTv+d0YKF/rolDcK+mK/rkxP3rtJA7Ud8nQ4VjxyYX4jTs3/BzDkP7Tsj +5gKy9e1zuTF+MUWs3G5oKGQUKVcbgoYJ+iOqgVSd1JbecRo7Pl8XgDv3I9RWHzUr +EAMjVJjRU9tJuPvILFBkpl1/OPC9sGxJz9Hy9qLtEGhGLUhNz6XmIy/aWPCyA4ea +ZES/n7f+aYmXIxulcxS7MUejkwl1EtNqVyrKvLiRBXjBk2HPCb7Te8fRu/LpHZXN +D7wjymg1fGZPPFzdKh7wMdAKiK50KIMGXTxS6kHb6qW/755oSUjWRLPGcPCfdbjn +UiC5WC9FCog6jfRq1rMlz5b8yjyb+UbJ6N4qFSHeQf+7WLeS0Di8k3cLDSWl6T7M +z82ePof2V2TrADNpXvAcR78uiDfUpfa7DhkimvbBZpRVaaQVU7unxUPVc93WgCWV +a7kBuFJAGt+Wt1LPPD/5KOQ5pRINSoh4VhiZzmnY/m7RDPWEaL5gsMjF5bFoP2UZ +MuyAiTmvO299lJDrdQyQds7yafO9PrTE4msuqpuZSHW7ZZIdRO6EXlfZ1We3icWr ++jE47bUIEl04k1PvXyv9LeoqlHZJTagxZIerMOEwq976MaVR7RJbqUpRUV9FFNCL +gTouPCwUcVtLCaTYQjz/+12/YeVkiBHIWkI8Vv5Mn3Vkwy303ygGCQ+brht1e8x+ +BbgzSpiX8aHiEuDAKooewxnKrf3Dk9BcwbnftxajOZcZ3iphk07t5VLRy86zLKCq +ZOY+KymcDCGaOPnSHFrZK3lZOOT+BB9Vi6EYAkxZCZgoDsb/voMEdpPlxK7ultf6 +is5/JQeQbeP9wbNh4Ru2x3p5Ir4wffhh1KT3UsMobusosTo55ErhMHPvH5amppwq +IrxdM7heo7JMaNKmtol4y45IqSt58iluF5m2Ds4m85xjDteRgEOjtNBStFxPCMAB +KUEzRxEaplAcJfzYzpYtoHZuZ8W3Gi7yeXQ+BV8Q9DeaZc5DDDhIcIkOoHOAKhit +d7Gpr8hpwc60AgHRjua8OdbhM4ntT1xnyDEqZbP8mN+UBAohOHMrqo+f4DL1ibB9 +qSwfdLiVItsEBqlfANV3i9rEeKNH5tOFwFCmmH1yBCSDCtWPmPUJ5tZae6fIetK5 +uSstFXLaDpm6fcHgkeqrnyteWpnk5X5SQQ+fMHPjQ2vp +-----END ENCRYPTED PRIVATE KEY----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem new file mode 100644 index 0000000000..0b0e128a25 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_key.pem @@ -0,0 +1,30 @@ +-----BEGIN RSA PRIVATE KEY----- +Proc-Type: 4,ENCRYPTED +DEK-Info: DES-EDE3-CBC,FB5DE36A7A8B25DA + +skR15rUvZmdLzGqU5/BF4Yc3E6dxtXTvlOhuGnqH/idItMKUMWIIlQ7ZfWYF/CrC +CkeAUqhF4y+y+2eR4ejUzZKs6bYjTtkXAXAqQvCsTrTBdQSCcLwbHWLWMro0UG24 +e23Rx8kD0YC7VHqyr08NlLh94wR7kanhEeRUbmKBonZT/I9AZ5ntiBxq9QVBtc8M +f7LKIsnQDcd39cVXSo3LOJ/x7YVB//Ln1R1dexwxE0sXOyLq2hhrxzfHGuGXXW41 +/3+CeTgmX9Rzpawrq9vbVabPUgFcJlrogNRSnUAm9kz4b2zadCxEaCejVmhBy4wx +z2AJGcmE+D4VkQK1AAj5+AQQrPOIIFQnyGjwHkJSTGVTcKmttRYZBvUjdfQfj1fK +NsKOSZLzZGknM8Pz5MHgHqk70C7f+nm0uVhVuAiykA4PY4JdCAuTWJxMM2LWM3/q +rYCEMwxCGa6U92dakfC+W+d9pAbeN+xYOWkDrqG7BdAYg1P70cuMRPdd5bsq3YPp +G4n5NVyQvLlocGhZgC7NVzUtc18+rGblV4D657+GZwJnBZJN4TYey4+r2D5fv9rO +kcRVwfR704BbUBkjIzVzD7nXtBbr3ni8HSqde3g4aVL4WyV9XNvjUsYyrZ0u9Mt1 +IccAsa1xBquUNMxwO1H1mFLtzPKmFzKtlzqiiDsRQoRylwUa1k03sHKUflZRa8Sf +g4MpTRzK+vo1opMemlonty5YbvWXKlH68ioo49L8N457Y0hIUJOQgywg80NxT33t +x8y66lawd1Iv+Q7pptVxJtA4JmcdPvGwBLJZY4DacMyp/JqchAQfSQfmQ0tC+RfJ +z2By/s5wOEuVDksgp8RF1gn+VmvLyOoLK7tq+zpMO1mhfYTCMgSiz2GkNdiW6i25 +gjNWN/F62YL+9VJo4+olrcsYDFiiJq+deQk3H1tQJzu6qECfDqKDyw7IunvTwFil +5/d43LvLbRj75Kf/++xwTjfHudeTgw02/yPyELnURkUazvkOFsn7n8tU46Qm5TWh +fPFXSYxRf3m9rkKZB98YOJo595RuZyiYg9dEQX8Gybl1/7H7l4Cvw6yp71kgLrrI +JRYEt9pmWbQX97UFC3WTVMdKWakFziYVGPvFKkIzrHgcutbQVNsZ7GbO+rdWMIxr +SfUe6jCEclzGQjI9Ep4PTLjZvbusUMkoUjGasAluXFXDC4RKtpuXd4RmbOLdVuyN +OnZ5KZHFjrv4ch5PakRTViWFWSddV5CJ4fMkCG9qUHKrUWGjOvzu5rbcUzq3xJZG +9loIvlA4ekEAhQPHwx69uBmUwnCgyB9CosQGmUlwmC3KALA/EiXklTA6w0fGiiPk +uLA9oBGrVcD8Peug9Owfmj4fWbxJGP7x1UR/nZWpynIfzME0AD8MK5uqoWmQTG8I +cLSjVAB1CO//AZe4LpYQulMPq4dipmE+YnKLi0WPXuZVARDciAGGV2BfH6Iv8j9k +o9IoklcpGg22zXLoGn4tu+7Y5GcoV/mx68Gun1E/QFuY59damAqoc82EEsxr+UX0 +4vGX+KZn283xSYiilE3qpCZOER0ZUFInphUwJzzYfW3mW/AWR78tFQIQiuVKV2/a +-----END RSA PRIVATE KEY----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem new file mode 100644 index 0000000000..8a92a68908 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +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 +wOqb/axEbvcj5sV6/4p2zz6AzFPEmQ== +-----END PRIVATE KEY----- From f23b249abcc8caf1306aa8192d2a28b212940d77 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Tue, 17 Oct 2023 17:15:23 +0300 Subject: [PATCH 186/267] UI: Improvement default widget bundle in attributes/timeseries tables --- .../home/components/attribute/attribute-table.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 119c7a829f..8bd711b175 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 @@ -501,7 +501,7 @@ export class AttributeTableComponent extends PageComponent implements AfterViewI this.widgetsLoaded = false; this.widgetBundleSet = false; this.widgetsCarouselIndex = 0; - this.selectedWidgetsBundleAlias = 'cards'; + this.selectedWidgetsBundleAlias = 'tables'; const entityAlias: EntityAlias = { id: this.utils.guid(), From 71dd96b08447b707015ff3cab5ae445a8b973be6 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 17 Oct 2023 18:00:04 +0300 Subject: [PATCH 187/267] Fix the widgets_bundle_widget table after upgrade --- application/src/main/data/upgrade/3.5.1/schema_update.sql | 2 +- application/src/main/data/upgrade/3.6.0/schema_update.sql | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/application/src/main/data/upgrade/3.5.1/schema_update.sql b/application/src/main/data/upgrade/3.5.1/schema_update.sql index f41e370ab5..fab91a4e67 100644 --- a/application/src/main/data/upgrade/3.5.1/schema_update.sql +++ b/application/src/main/data/upgrade/3.5.1/schema_update.sql @@ -189,7 +189,7 @@ DO $$ BEGIN IF EXISTS(SELECT 1 FROM information_schema.columns WHERE table_name = 'widget_type' and column_name='bundle_alias') THEN - INSERT INTO widgets_bundle_widget SELECT wb.id as widgets_bundle_id, wt.id as widget_type_id from widget_type wt left join widgets_bundle wb ON wt.bundle_alias = wb.alias ON CONFLICT (widgets_bundle_id, widget_type_id) DO NOTHING; + INSERT INTO widgets_bundle_widget SELECT wb.id as widgets_bundle_id, wt.id as widget_type_id from widget_type wt left join widgets_bundle wb ON wt.bundle_alias = wb.alias AND wt.tenant_id = wb.tenant_id ON CONFLICT (widgets_bundle_id, widget_type_id) DO NOTHING; ALTER TABLE widget_type DROP COLUMN IF EXISTS bundle_alias; END IF; END; diff --git a/application/src/main/data/upgrade/3.6.0/schema_update.sql b/application/src/main/data/upgrade/3.6.0/schema_update.sql index 0ad2d97b7a..ee1b311de2 100644 --- a/application/src/main/data/upgrade/3.6.0/schema_update.sql +++ b/application/src/main/data/upgrade/3.6.0/schema_update.sql @@ -24,3 +24,10 @@ ALTER TABLE notification DROP CONSTRAINT IF EXISTS fk_notification_request_id; ALTER TABLE notification DROP CONSTRAINT IF EXISTS fk_notification_recipient_id; CREATE INDEX IF NOT EXISTS idx_notification_notification_request_id ON notification(request_id); CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id ON notification_request(tenant_id); + +-- DELETE invalid records from M:N widgets_bundle_widget table caused by the bug in previous upgrade script; +DELETE +FROM widgets_bundle_widget wbw +WHERE (SELECT tenant_id FROM widgets_bundle wb WHERE wb.id = wbw.widgets_bundle_id) != + (SELECT tenant_id FROM widget_type WHERE id = wbw.widget_type_id); + From 3946b058cdda60fbdfb03d92d0c60fb3d1399605 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Oct 2023 18:09:38 +0300 Subject: [PATCH 188/267] Do not push ALARM update to edge automatically - only using push to edge rule node --- .../service/edge/EdgeEventSourcingListener.java | 10 +++++----- .../thingsboard/server/edge/AlarmEdgeTest.java | 15 --------------- ui-ngx/src/app/core/http/entity.service.ts | 10 +++++++--- 3 files changed, 12 insertions(+), 23 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java index 707dbec964..006af577c9 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/EdgeEventSourcingListener.java @@ -25,6 +25,7 @@ import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.cluster.TbClusterService; import org.thingsboard.server.common.data.OtaPackageInfo; import org.thingsboard.server.common.data.User; +import org.thingsboard.server.common.data.alarm.Alarm; import org.thingsboard.server.common.data.alarm.AlarmApiCallResult; import org.thingsboard.server.common.data.edge.EdgeEventActionType; import org.thingsboard.server.common.data.edge.EdgeEventType; @@ -78,7 +79,7 @@ public class EdgeEventSourcingListener { return; } try { - if (!isValidEdgeEventEntity(event.getEntity(), event.getOldEntity())) { + if (!isValidSaveEntityEventForEdgeProcessing(event.getEntity(), event.getOldEntity())) { return; } log.trace("[{}] SaveEntityEvent called: {}", event.getTenantId(), event); @@ -141,7 +142,7 @@ public class EdgeEventSourcingListener { } } - private boolean isValidEdgeEventEntity(Object entity, Object oldEntity) { + private boolean isValidSaveEntityEventForEdgeProcessing(Object entity, Object oldEntity) { if (entity instanceof OtaPackageInfo) { OtaPackageInfo otaPackageInfo = (OtaPackageInfo) entity; return otaPackageInfo.hasUrl() || otaPackageInfo.isHasData(); @@ -159,9 +160,8 @@ public class EdgeEventSourcingListener { cleanUpUserAdditionalInfo(user); return !user.equals(oldUser); } - } else if (entity instanceof AlarmApiCallResult) { - AlarmApiCallResult alarmApiCallResult = (AlarmApiCallResult) entity; - return alarmApiCallResult.isModified(); + } else if (entity instanceof AlarmApiCallResult || entity instanceof Alarm) { + return false; } // Default: If the entity doesn't match any of the conditions, consider it as valid. return true; diff --git a/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java index afccc634ed..259572851c 100644 --- a/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/AlarmEdgeTest.java @@ -19,7 +19,6 @@ import com.fasterxml.jackson.core.type.TypeReference; import com.google.protobuf.AbstractMessage; import org.junit.Assert; import org.junit.Test; -import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.alarm.Alarm; @@ -102,20 +101,6 @@ public class AlarmEdgeTest extends AbstractEdgeTest { Assert.assertEquals(savedAlarm.getStatus().name(), alarmUpdateMsg.getStatus()); Assert.assertEquals(savedAlarm.getSeverity().name(), alarmUpdateMsg.getSeverity()); - // update alarm - String updatedDetails = "{\"testKey\":\"testValue\"}"; - savedAlarm.setDetails(JacksonUtil.OBJECT_MAPPER.readTree(updatedDetails)); - edgeImitator.expectMessageAmount(1); - savedAlarm = doPost("/api/alarm", savedAlarm, Alarm.class); - Assert.assertTrue(edgeImitator.waitForMessages()); - latestMessage = edgeImitator.getLatestMessage(); - Assert.assertTrue(latestMessage instanceof AlarmUpdateMsg); - alarmUpdateMsg = (AlarmUpdateMsg) latestMessage; - Assert.assertEquals(UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, alarmUpdateMsg.getMsgType()); - Assert.assertEquals(savedAlarm.getUuidId().getMostSignificantBits(), alarmUpdateMsg.getIdMSB()); - Assert.assertEquals(savedAlarm.getUuidId().getLeastSignificantBits(), alarmUpdateMsg.getIdLSB()); - Assert.assertEquals(updatedDetails, alarmUpdateMsg.getDetails()); - // ack alarm edgeImitator.expectMessageAmount(1); doPost("/api/alarm/" + savedAlarm.getUuidId() + "/ack"); diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index 12f6300b93..cc1dd13345 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -92,6 +92,7 @@ import { NotificationService } from '@core/http/notification.service'; import { TenantProfileService } from '@core/http/tenant-profile.service'; import { NotificationType } from '@shared/models/notification.models'; import { UserId } from '@shared/models/id/user-id'; +import { AlarmService } from '@core/http/alarm.service'; @Injectable({ providedIn: 'root' @@ -119,7 +120,8 @@ export class EntityService { private assetProfileService: AssetProfileService, private utils: UtilsService, private queueService: QueueService, - private notificationService: NotificationService + private notificationService: NotificationService, + private alarmService: AlarmService ) { } private getEntityObservable(entityType: EntityType, entityId: string, @@ -155,7 +157,7 @@ export class EntityService { observable = this.ruleChainService.getRuleChain(entityId, config); break; case EntityType.ALARM: - console.error('Get Alarm Entity is not implemented!'); + observable = this.alarmService.getAlarm(entityId, config); break; case EntityType.OTA_PACKAGE: observable = this.otaPackageService.getOtaPackageInfo(entityId, config); @@ -238,7 +240,9 @@ export class EntityService { entityIds); break; case EntityType.ALARM: - console.error('Get Alarm Entity is not implemented!'); + observable = this.getEntitiesByIdsObservable( + (id) => this.alarmService.getAlarm(id, config), + entityIds); break; case EntityType.DEVICE_PROFILE: observable = this.getEntitiesByIdsObservable( From 1320881a19fcd52ea12d1180aead6f1cd9054642 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 17 Oct 2023 18:30:17 +0300 Subject: [PATCH 189/267] UI: Implement 'Progress bar' widget. --- .../json/system/widget_bundles/cards.json | 1 + .../widget_bundles/status_indicators.json | 3 +- .../system/widget_types/progress_bar.json | 26 ++ .../basic/basic-widget-config.module.ts | 12 +- .../progress-bar-basic-config.component.html | 171 ++++++++++++ .../progress-bar-basic-config.component.ts | 262 ++++++++++++++++++ .../cards/progress-bar-widget.component.html | 42 +++ .../cards/progress-bar-widget.component.scss | 84 ++++++ .../cards/progress-bar-widget.component.ts | 221 +++++++++++++++ .../lib/cards/progress-bar-widget.models.ts | 98 +++++++ .../battery-level-widget.component.scss | 5 +- .../battery-level-widget.component.ts | 1 + ...rogress-bar-widget-settings.component.html | 94 +++++++ .../progress-bar-widget-settings.component.ts | 133 +++++++++ .../lib/settings/widget-settings.module.ts | 12 +- ...wind-speed-direction-widget.component.scss | 5 +- .../widget/widget-components.module.ts | 7 +- .../assets/locale/locale.constant-en_US.json | 16 ++ .../widget/progress-bar/default-layout.svg | 38 +++ .../widget/progress-bar/simplified-layout.svg | 36 +++ ui-ngx/src/form.scss | 7 + 21 files changed, 1263 insertions(+), 11 deletions(-) create mode 100644 application/src/main/data/json/system/widget_types/progress_bar.json create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.scss create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.models.ts create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.html create mode 100644 ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.ts create mode 100644 ui-ngx/src/assets/widget/progress-bar/default-layout.svg create mode 100644 ui-ngx/src/assets/widget/progress-bar/simplified-layout.svg 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 d49db3581d..c1420e6549 100644 --- a/application/src/main/data/json/system/widget_bundles/cards.json +++ b/application/src/main/data/json/system/widget_bundles/cards.json @@ -12,6 +12,7 @@ "cards.horizontal_value_card", "cards.aggregated_value_card", "simple_value_and_chart_card", + "progress_bar", "cards.label_widget", "cards.dashboard_state_widget", "cards.qr_code", diff --git a/application/src/main/data/json/system/widget_bundles/status_indicators.json b/application/src/main/data/json/system/widget_bundles/status_indicators.json index e175ffa5bb..429d3fe016 100644 --- a/application/src/main/data/json/system/widget_bundles/status_indicators.json +++ b/application/src/main/data/json/system/widget_bundles/status_indicators.json @@ -9,6 +9,7 @@ }, "widgetTypeFqns": [ "battery_level", - "signal_strength" + "signal_strength", + "progress_bar" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/progress_bar.json b/application/src/main/data/json/system/widget_types/progress_bar.json new file mode 100644 index 0000000000..df3dcf6268 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/progress_bar.json @@ -0,0 +1,26 @@ +{ + "fqn": "progress_bar", + "name": "Progress bar", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAeFBMVEXg4ODf39/g4ODg4OAAAAD////g4OD19fUhISE/Ut3j4+OsrKzHx8eQkJB0dHQ8PDzx8fEvLy+6urrV1dWCgoJYWFienp5KSkrv7++GhoZmZmaXl5f39/epqanLy8vCwsL29vZtfORiceJ+fn7m5ubU1NTn6fve4fIbcz38AAAABXRSTlPvIL+vAC9A4IoAAASZSURBVHja7d0NT9swEIDhMji4nb/jxEk/NmCM7f//w/niQLtJyxamtdfiF6EmDkh+1Di0IojVzdWH1e25d311s7paDXD2+cy49nABDfm0gotodSmQ2woRVoVIq0KkVSHSqhBpVYi0KkRaFSKtGUijctrDv6XQwEzHgDjkXLoAiKaoAurzhxAAGGxBm2gMgE+25SHeUNE0QKbRNo/otlWQo2QNQa6xrdpD1DSqW6vyBhmtrD86RKHNGIcOyOUHZJDDEEIe1xgQdT487gGF0CNmgUXnsH+BhPzhCKDFfNh50OgQ6dgQv0HFEB2hw8QYDQo3HlqGZFf0066GDiNQFmvcMEZNEMdH2zza8WhivopwVEjX9QF7yBCVSbwFCc04YdBoy4xhkw3QYAsWjQciiNhH8OT3a8RnXo4ooRm/M3dMSN91m+QnCM+6zN9h2ShTyq4xy08X9mpcVxgswR4yfktymDsJhICbIPEA4n+GJJXTfNS48atIWQzxABKQl0YEJQDiQ/Dl1LeoDyHtONWYj41TDtDYvJMwTZA2w7ADwwNJAAQS9sqgY4NLyb1CKGCrGNeh0QY7Pq6bHvUEQaMcKh5VJkiAgAmIHfGGw7B5hQD1iMHkR4vlC5TLA+l1jeS9dlo5LdojQeYj/7rBp8xrnvz+kSOCg349WjolpES9itphBEm9BeI3OJ46omLI8qhppP2e6z28sTqvKkRaFSKtCpFWhUirQqRVIdKqEGlViLQqRFoVIq0KkVaFSKtCpFUh0qoQaVWItCpEWhUirQqR1jzER609HEbSbhT4G4g3AXOWYKrpAnYgszlIjyVXJNTl7XOEJMQ+ArXT5L3LpBQJZDYD6RGJAQED5DKoBbnN3uTfvIAAgBB7EFyBzBbQlXsTNV/EQGh/hPgWUZW7e1PglR+hJOw6PA/RfCs2Gsg5nApFYvtO1L2A8xC1n3ne6DWQRewKEfQGSM7FeB5CSrUOUY0QN13D0DPEQuzANiAlhsxHAYNnSA9ci6gZ5Jq2VRbEVCCzWcRYrl2cKRAgk6gT9NPx9xBvbTqYeofBTyz9IlTaiDm3Zp6RckoxAePIScxzGKBEPTnVK5DRDMS+vtZyLMguBbTZv1BxpAw0UpbJDMQ7LAWCXIMl52EsGVAtKCmvv2YgQNYxY0PTbs97xh9SN07KemfITFHHw4nzntA3jO/kPfsZVSHSqhBpVYi0KkRaFSKtCpHWO4B8e/y4rC/f7/5/D8shXz4u7fHuCO0WQz4u7+4YLYY8LnZ8uTtCu+VrZOm59XiMNbJ7x1etM6tCpFUh0qoQac1A7s325L+P2t1/AoBhu90O04SWQ4b1ANsTP10Pa7XOD5/u4fMWbte74WlYDnlOAM3Jn5KBIesBHp7gXmXS5+WQz5/EQOz42TQVIgWyHgDyqfVGyPD0AOkZThxD+JrznBf7NpO+LodAszZbOHEF8nW9ZYEyZvnll9vtQErDNKH3/ZP9vKoQaVWItCpEWhUirQqRVoVIq0KkVSHSqhBpVYi0LgiygovodvXhAv71NIC/Xl2txPzpxNsbMuPm6vr23Ft9uLr5AdpbpSAPQyy7AAAAAElFTkSuQmCC", + "description": "Displays any value reading as a horizontal progress bar. Allows to configure value range, bar colors, and other settings.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 2, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-progress-bar-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-progress-bar-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":0,\"tickMax\":100,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Progress bar\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "progress" + ] +} \ No newline at end of file diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts index fd0e48322d..c26cf43542 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/basic-widget-config.module.ts @@ -67,6 +67,9 @@ import { import { ValueChartCardBasicConfigComponent } from '@home/components/widget/config/basic/cards/value-chart-card-basic-config.component'; +import { + ProgressBarBasicConfigComponent +} from '@home/components/widget/config/basic/cards/progress-bar-basic-config.component'; @NgModule({ declarations: [ @@ -87,7 +90,8 @@ import { BatteryLevelBasicConfigComponent, WindSpeedDirectionBasicConfigComponent, SignalStrengthBasicConfigComponent, - ValueChartCardBasicConfigComponent + ValueChartCardBasicConfigComponent, + ProgressBarBasicConfigComponent ], imports: [ CommonModule, @@ -112,7 +116,8 @@ import { BatteryLevelBasicConfigComponent, WindSpeedDirectionBasicConfigComponent, SignalStrengthBasicConfigComponent, - ValueChartCardBasicConfigComponent + ValueChartCardBasicConfigComponent, + ProgressBarBasicConfigComponent ] }) export class BasicWidgetConfigModule { @@ -131,5 +136,6 @@ export const basicWidgetConfigComponentsMap: {[key: string]: Type + + + + + +
+
widget-config.appearance
+ + + {{ progressBarLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.progress-bar.auto-scale' | translate }} + +
+
+ + {{ 'widget-config.title' | translate }} + +
+ + + + + + + +
+
+
+ + {{ 'widgets.progress-bar.icon' | translate }} + +
+ + + + + + + + +
+
+
+ + {{ 'widgets.progress-bar.value' | translate }} + +
+ + + +
widget-config.decimals-suffix
+
+ + + + +
+
+
+
{{ 'widgets.progress-bar.range' | translate }}
+
+
widgets.progress-bar.min
+ + + +
widgets.progress-bar.max
+ + + +
+
+
+ + {{ 'widgets.progress-bar.range-ticks' | translate }} + +
+ + + + +
+
+
+
+
widgets.progress-bar.bar
+
+
{{ 'widgets.progress-bar.bar-color' | translate }}
+ + +
+
+
{{ 'widgets.progress-bar.bar-background' | translate }}
+ + +
+
+
+
widget-config.card-appearance
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
widget-config.show-card-buttons
+ + {{ 'fullscreen.fullscreen' | translate }} + +
+
+
{{ 'widget-config.card-border-radius' | translate }}
+ + + +
+
+ + +
diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts new file mode 100644 index 0000000000..ef54d64861 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts @@ -0,0 +1,262 @@ +/// +/// Copyright © 2016-2023 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 { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; +import { WidgetConfigComponentData } from '@home/models/widget-component.models'; +import { + datasourcesHasAggregation, + datasourcesHasOnlyComparisonAggregation, + WidgetConfig, +} from '@shared/models/widget.models'; +import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; +import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; +import { + getTimewindowConfig, + setTimewindowConfig +} from '@home/components/widget/config/timewindow-config-panel.component'; +import { formatValue, isUndefined } from '@core/utils'; +import { cssSizeToStrSize, resolveCssSize } from '@shared/models/widget-settings.models'; +import { + progressBarDefaultSettings, + ProgressBarLayout, + progressBarLayoutImages, + progressBarLayouts, + progressBarLayoutTranslations, + ProgressBarWidgetSettings +} from '@home/components/widget/lib/cards/progress-bar-widget.models'; + +@Component({ + selector: 'tb-progress-bar-basic-config', + templateUrl: './progress-bar-basic-config.component.html', + styleUrls: ['../basic-config.scss'] +}) +export class ProgressBarBasicConfigComponent extends BasicWidgetConfigComponent { + + public get displayTimewindowConfig(): boolean { + const datasources = this.progressBarWidgetConfigForm.get('datasources').value; + return datasourcesHasAggregation(datasources); + } + + public onlyHistoryTimewindow(): boolean { + const datasources = this.progressBarWidgetConfigForm.get('datasources').value; + return datasourcesHasOnlyComparisonAggregation(datasources); + } + + progressBarLayout = ProgressBarLayout; + + progressBarLayouts = progressBarLayouts; + + progressBarLayoutTranslationMap = progressBarLayoutTranslations; + progressBarLayoutImageMap = progressBarLayoutImages; + + progressBarWidgetConfigForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + constructor(protected store: Store, + protected widgetConfigComponent: WidgetConfigComponent, + private fb: UntypedFormBuilder) { + super(store, widgetConfigComponent); + } + + protected configForm(): UntypedFormGroup { + return this.progressBarWidgetConfigForm; + } + + protected setupDefaults(configData: WidgetConfigComponentData) { + this.setupDefaultDatasource(configData, [{ name: 'humidity', label: 'humidity', type: DataKeyType.timeseries }]); + } + + protected onConfigSet(configData: WidgetConfigComponentData) { + const settings: ProgressBarWidgetSettings = {...progressBarDefaultSettings, ...(configData.config.settings || {})}; + const iconSize = resolveCssSize(configData.config.iconSize); + this.progressBarWidgetConfigForm = this.fb.group({ + timewindowConfig: [getTimewindowConfig(configData.config), []], + datasources: [configData.config.datasources, []], + + layout: [settings.layout, []], + autoScale: [settings.autoScale, []], + + showTitle: [configData.config.showTitle, []], + title: [configData.config.title, []], + titleFont: [configData.config.titleFont, []], + titleColor: [configData.config.titleColor, []], + + showIcon: [configData.config.showTitleIcon, []], + iconSize: [iconSize[0], [Validators.min(0)]], + iconSizeUnit: [iconSize[1], []], + icon: [configData.config.titleIcon, []], + iconColor: [configData.config.iconColor, []], + + showValue: [settings.showValue, []], + units: [configData.config.units, []], + decimals: [configData.config.decimals, []], + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + tickMin: [settings.tickMin, []], + tickMax: [settings.tickMax, []], + + showTicks: [settings.showTicks, []], + ticksFont: [settings.ticksFont, []], + ticksColor: [settings.ticksColor, []], + + barColor: [settings.barColor, []], + barBackground: [settings.barBackground, []], + + background: [settings.background, []], + + cardButtons: [this.getCardButtons(configData.config), []], + borderRadius: [configData.config.borderRadius, []], + + actions: [configData.config.actions || {}, []] + }); + } + + protected prepareOutputConfig(config: any): WidgetConfigComponentData { + setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); + this.widgetConfig.config.datasources = config.datasources; + + this.widgetConfig.config.showTitle = config.showTitle; + this.widgetConfig.config.title = config.title; + this.widgetConfig.config.titleFont = config.titleFont; + this.widgetConfig.config.titleColor = config.titleColor; + + this.widgetConfig.config.showTitleIcon = config.showIcon; + this.widgetConfig.config.iconSize = cssSizeToStrSize(config.iconSize, config.iconSizeUnit); + this.widgetConfig.config.titleIcon = config.icon; + this.widgetConfig.config.iconColor = config.iconColor; + + this.widgetConfig.config.settings = this.widgetConfig.config.settings || {}; + + this.widgetConfig.config.settings.layout = config.layout; + this.widgetConfig.config.settings.autoScale = config.autoScale; + + this.widgetConfig.config.settings.showValue = config.showValue; + this.widgetConfig.config.units = config.units; + this.widgetConfig.config.decimals = config.decimals; + this.widgetConfig.config.settings.valueFont = config.valueFont; + this.widgetConfig.config.settings.valueColor = config.valueColor; + + this.widgetConfig.config.settings.tickMin = config.tickMin; + this.widgetConfig.config.settings.tickMax = config.tickMax; + + this.widgetConfig.config.settings.showTicks = config.showTicks; + this.widgetConfig.config.settings.ticksFont = config.ticksFont; + this.widgetConfig.config.settings.ticksColor = config.ticksColor; + + this.widgetConfig.config.settings.barColor = config.barColor; + this.widgetConfig.config.settings.barBackground = config.barBackground; + + this.widgetConfig.config.settings.background = config.background; + + this.setCardButtons(config.cardButtons, this.widgetConfig.config); + this.widgetConfig.config.borderRadius = config.borderRadius; + + this.widgetConfig.config.actions = config.actions; + return this.widgetConfig; + } + + protected validatorTriggers(): string[] { + return ['showTitle', 'showIcon', 'showValue', 'showTicks', 'layout']; + } + + protected updateValidators(emitEvent: boolean, trigger?: string) { + const showTitle: boolean = this.progressBarWidgetConfigForm.get('showTitle').value; + const showIcon: boolean = this.progressBarWidgetConfigForm.get('showIcon').value; + const showValue: boolean = this.progressBarWidgetConfigForm.get('showValue').value; + const showTicks: boolean = this.progressBarWidgetConfigForm.get('showTicks').value; + const layout: ProgressBarLayout = this.progressBarWidgetConfigForm.get('layout').value; + + const ticksEnabled = layout === ProgressBarLayout.default; + + if (showTitle) { + this.progressBarWidgetConfigForm.get('title').enable(); + this.progressBarWidgetConfigForm.get('titleFont').enable(); + this.progressBarWidgetConfigForm.get('titleColor').enable(); + this.progressBarWidgetConfigForm.get('showIcon').enable({emitEvent: false}); + if (showIcon) { + this.progressBarWidgetConfigForm.get('iconSize').enable(); + this.progressBarWidgetConfigForm.get('iconSizeUnit').enable(); + this.progressBarWidgetConfigForm.get('icon').enable(); + this.progressBarWidgetConfigForm.get('iconColor').enable(); + } else { + this.progressBarWidgetConfigForm.get('iconSize').disable(); + this.progressBarWidgetConfigForm.get('iconSizeUnit').disable(); + this.progressBarWidgetConfigForm.get('icon').disable(); + this.progressBarWidgetConfigForm.get('iconColor').disable(); + } + } else { + this.progressBarWidgetConfigForm.get('title').disable(); + this.progressBarWidgetConfigForm.get('titleFont').disable(); + this.progressBarWidgetConfigForm.get('titleColor').disable(); + this.progressBarWidgetConfigForm.get('showIcon').disable({emitEvent: false}); + this.progressBarWidgetConfigForm.get('iconSize').disable(); + this.progressBarWidgetConfigForm.get('iconSizeUnit').disable(); + this.progressBarWidgetConfigForm.get('icon').disable(); + this.progressBarWidgetConfigForm.get('iconColor').disable(); + } + + if (showValue) { + this.progressBarWidgetConfigForm.get('units').enable(); + this.progressBarWidgetConfigForm.get('decimals').enable(); + this.progressBarWidgetConfigForm.get('valueFont').enable(); + this.progressBarWidgetConfigForm.get('valueColor').enable(); + } else { + this.progressBarWidgetConfigForm.get('units').disable(); + this.progressBarWidgetConfigForm.get('decimals').disable(); + this.progressBarWidgetConfigForm.get('valueFont').disable(); + this.progressBarWidgetConfigForm.get('valueColor').disable(); + } + + if (ticksEnabled) { + this.progressBarWidgetConfigForm.get('showTicks').enable({emitEvent: false}); + if (showTicks) { + this.progressBarWidgetConfigForm.get('ticksFont').enable(); + this.progressBarWidgetConfigForm.get('ticksColor').enable(); + } else { + this.progressBarWidgetConfigForm.get('ticksFont').disable(); + this.progressBarWidgetConfigForm.get('ticksColor').disable(); + } + } else { + this.progressBarWidgetConfigForm.get('showTicks').disable({emitEvent: false}); + this.progressBarWidgetConfigForm.get('ticksFont').disable(); + this.progressBarWidgetConfigForm.get('ticksColor').disable(); + } + } + + private getCardButtons(config: WidgetConfig): string[] { + const buttons: string[] = []; + if (isUndefined(config.enableFullscreen) || config.enableFullscreen) { + buttons.push('fullscreen'); + } + return buttons; + } + + private setCardButtons(buttons: string[], config: WidgetConfig) { + config.enableFullscreen = buttons.includes('fullscreen'); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(78, decimals, units, true); + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.html new file mode 100644 index 0000000000..3f788aaf82 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.html @@ -0,0 +1,42 @@ + +
+
+
+ + + +
+
+ + + +
{{ valueText }}
+
+
+
+
+
+
+
{{ settings.tickMin }}
+
{{ settings.tickMax }}
+
+
+
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.scss new file mode 100644 index 0000000000..7f83997987 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.scss @@ -0,0 +1,84 @@ +/** + * Copyright © 2016-2023 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-progress-bar-panel { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 20px 24px 24px 24px; + > div:not(.tb-progress-bar-overlay) { + z-index: 1; + } + .tb-progress-bar-overlay { + position: absolute; + top: 12px; + left: 12px; + bottom: 12px; + right: 12px; + } + div.tb-widget-title { + padding: 0; + } + .tb-progress-bar-container { + width: 100%; + height: 100%; + position: relative; + display: flex; + flex-direction: column; + justify-content: space-between; + align-items: flex-start; + &.simplified { + justify-content: center; + } + } + .tb-progress-bar-content { + display: flex; + flex-direction: column; + align-self: stretch; + gap: 4px; + .tb-progress-bar-title-value-row { + display: flex; + flex-direction: row; + justify-content: space-between; + &.flex-end { + justify-content: flex-end; + } + .tb-progress-bar-value { + white-space: nowrap; + } + } + .tb-progress-bar { + display: flex; + flex-direction: column; + .tb-progress-bar-background { + border-radius: 12px; + .tb-progress-bar-progress { + height: 5px; + border-radius: 8px; + transition: background-color .2s, width .2s; + } + } + .tb-progress-bar-ticks { + display: flex; + flex-direction: row; + justify-content: space-between; + } + } + } +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts new file mode 100644 index 0000000000..fe1ac58ab4 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts @@ -0,0 +1,221 @@ +/// +/// Copyright © 2016-2023 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 { + AfterViewInit, + ChangeDetectorRef, + Component, + ElementRef, + Input, + OnDestroy, + OnInit, + Renderer2, + TemplateRef, + ViewChild, + ViewEncapsulation +} from '@angular/core'; +import { WidgetContext } from '@home/models/widget-component.models'; +import { formatValue, isDefinedAndNotNull, isNumeric } from '@core/utils'; +import { DatePipe } from '@angular/common'; +import { + backgroundStyle, + ColorProcessor, + ComponentStyle, + getDataKey, + getSingleTsValue, + overlayStyle, + resolveCssSize, + textStyle +} from '@shared/models/widget-settings.models'; +import { WidgetComponent } from '@home/components/widget/widget.component'; +import { progressBarDefaultSettings, ProgressBarLayout, ProgressBarWidgetSettings } from './progress-bar-widget.models'; +import { ResizeObserver } from '@juggle/resize-observer'; + +const defaultLayoutHeight = 80; +const simplifiedLayoutHeight = 75; +const defaultAspect = defaultLayoutHeight / 150; +const simplifiedAspect = simplifiedLayoutHeight / 150; + +@Component({ + selector: 'tb-progress-bar-widget', + templateUrl: './progress-bar-widget.component.html', + styleUrls: ['./progress-bar-widget.component.scss'], + encapsulation: ViewEncapsulation.None +}) +export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewInit { + + @ViewChild('progressBarPanel', {static: true}) + progressBarPanel: ElementRef; + + @ViewChild('progressBarContainer', {static: true}) + progressBarContainer: ElementRef; + + progressBarLayout = ProgressBarLayout; + + settings: ProgressBarWidgetSettings; + + @Input() + ctx: WidgetContext; + + @Input() + widgetTitlePanel: TemplateRef; + + layout: ProgressBarLayout; + + layoutClass = ''; + + showTitleValueRow = true; + titleValueRowClass = ''; + + showValue = true; + valueText = 'N/A'; + valueStyle: ComponentStyle = {}; + valueColor: ColorProcessor; + + barWidth = '0%'; + barColor: ColorProcessor; + + showTicks = true; + ticksStyle: ComponentStyle = {}; + + value: number; + + backgroundStyle: ComponentStyle = {}; + overlayStyle: ComponentStyle = {}; + + progressBarPanelResize$: ResizeObserver; + + private decimals = 0; + private units = ''; + + constructor(private date: DatePipe, + private widgetComponent: WidgetComponent, + private renderer: Renderer2, + private cd: ChangeDetectorRef) { + } + + ngOnInit(): void { + this.ctx.$scope.progressBarWidget = this; + this.settings = {...progressBarDefaultSettings, ...this.ctx.settings}; + + this.decimals = this.ctx.decimals; + this.units = this.ctx.units; + const dataKey = getDataKey(this.ctx.datasources); + if (isDefinedAndNotNull(dataKey?.decimals)) { + this.decimals = dataKey.decimals; + } + if (dataKey?.units) { + this.units = dataKey.units; + } + + this.layout = this.settings.layout; + + this.showValue = this.settings.showValue; + this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); + + this.showTitleValueRow = this.showValue || + (this.layout === ProgressBarLayout.simplified && this.widgetComponent.dashboardWidget.showWidgetTitlePanel); + + this.layoutClass = (this.layout === ProgressBarLayout.simplified || !this.widgetComponent.dashboardWidget.showWidgetTitlePanel) + ? 'simplified' : ''; + + this.titleValueRowClass = (this.layout === ProgressBarLayout.simplified && + !this.widgetComponent.dashboardWidget.showWidgetTitlePanel) ? 'flex-end' : ''; + + this.barColor = ColorProcessor.fromSettings(this.settings.barColor); + + this.showTicks = this.settings.showTicks && this.layout === ProgressBarLayout.default; + if (this.showTicks) { + this.ticksStyle = textStyle(this.settings.ticksFont, '0.1px'); + this.ticksStyle.color = this.settings.ticksColor; + } + + this.backgroundStyle = backgroundStyle(this.settings.background); + this.overlayStyle = overlayStyle(this.settings.background.overlay); + } + + ngAfterViewInit() { + if (this.settings.autoScale) { + this.renderer.setStyle(this.progressBarContainer.nativeElement, 'overflow', 'visible'); + this.renderer.setStyle(this.progressBarContainer.nativeElement, 'position', 'absolute'); + this.progressBarPanelResize$ = new ResizeObserver(() => { + this.onResize(); + }); + this.progressBarPanelResize$.observe(this.progressBarPanel.nativeElement); + this.onResize(); + } + } + + ngOnDestroy() { + } + + public onInit() { + const borderRadius = this.ctx.$widgetElement.css('borderRadius'); + this.overlayStyle = {...this.overlayStyle, ...{borderRadius}}; + this.cd.detectChanges(); + } + + public onDataUpdated() { + const tsValue = getSingleTsValue(this.ctx.data); + this.value = 0; + if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { + this.value = tsValue[1]; + this.valueText = formatValue(this.value, this.decimals, this.units, true); + } else { + this.valueText = 'N/A'; + } + this.valueColor.update(this.value); + this.barColor.update(this.value); + const range = this.settings.tickMax - this.settings.tickMin; + this.barWidth = `${(this.value / range) * 100}%`; + this.cd.detectChanges(); + } + + private onResize() { + const paddingLeft = getComputedStyle(this.progressBarPanel.nativeElement).paddingLeft; + const paddingRight = getComputedStyle(this.progressBarPanel.nativeElement).paddingRight; + const paddingTop = getComputedStyle(this.progressBarPanel.nativeElement).paddingTop; + const paddingBottom = getComputedStyle(this.progressBarPanel.nativeElement).paddingBottom; + const pLeft = resolveCssSize(paddingLeft)[0]; + const pRight = resolveCssSize(paddingRight)[0]; + const pTop = resolveCssSize(paddingTop)[0]; + const pBottom = resolveCssSize(paddingBottom)[0]; + const panelWidth = this.progressBarPanel.nativeElement.getBoundingClientRect().width - (pLeft + pRight); + const panelHeight = this.progressBarPanel.nativeElement.getBoundingClientRect().height - (pTop + pBottom); + const defaultLayout = this.layout === ProgressBarLayout.default && this.widgetComponent.dashboardWidget.showWidgetTitlePanel; + let minAspect = defaultLayout ? defaultAspect : simplifiedAspect; + let layoutHeight = defaultLayout ? defaultLayoutHeight : simplifiedLayoutHeight; + if (!this.showTitleValueRow) { + minAspect -= (40 / 150); + layoutHeight -= 40; + } + if (!this.showTicks) { + minAspect -= (10 / 150); + layoutHeight -= 10; + } + const aspect = Math.min(panelHeight / panelWidth, minAspect); + const targetWidth = panelWidth; + const targetHeight = targetWidth * aspect; + const scale = targetHeight / layoutHeight; + const width = targetWidth / scale; + const height = panelHeight / scale; + this.renderer.setStyle(this.progressBarContainer.nativeElement, 'width', width + 'px'); + this.renderer.setStyle(this.progressBarContainer.nativeElement, 'height', height + 'px'); + this.renderer.setStyle(this.progressBarContainer.nativeElement, 'transform', `scale(${scale})`); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.models.ts new file mode 100644 index 0000000000..d0aff79ba5 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.models.ts @@ -0,0 +1,98 @@ +/// +/// Copyright © 2016-2023 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 { + BackgroundSettings, + BackgroundType, + ColorSettings, + constantColor, + Font +} from '@shared/models/widget-settings.models'; + +export enum ProgressBarLayout { + default = 'default', + simplified = 'simplified' +} + +export const progressBarLayouts = Object.keys(ProgressBarLayout) as ProgressBarLayout[]; + +export const progressBarLayoutTranslations = new Map( + [ + [ProgressBarLayout.default, 'widgets.progress-bar.layout-default'], + [ProgressBarLayout.simplified, 'widgets.progress-bar.layout-simplified'] + ] +); + +export const progressBarLayoutImages = new Map( + [ + [ProgressBarLayout.default, 'assets/widget/progress-bar/default-layout.svg'], + [ProgressBarLayout.simplified, 'assets/widget/progress-bar/simplified-layout.svg'] + ] +); + +export interface ProgressBarWidgetSettings { + layout: ProgressBarLayout; + autoScale: boolean; + showValue: boolean; + valueFont: Font; + valueColor: ColorSettings; + showTicks: boolean; + tickMin: number; + tickMax: number; + ticksFont: Font; + ticksColor: string; + barColor: ColorSettings; + barBackground: string; + background: BackgroundSettings; +} + +export const progressBarDefaultSettings: ProgressBarWidgetSettings = { + layout: ProgressBarLayout.default, + autoScale: true, + showValue: true, + valueFont: { + family: 'Roboto', + size: 24, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '32px' + }, + valueColor: constantColor('rgba(0, 0, 0, 0.87)'), + showTicks: true, + tickMin: 0, + tickMax: 100, + ticksFont: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '16px' + }, + ticksColor: 'rgba(0,0,0,0.54)', + barColor: constantColor('rgba(63, 82, 221, 1)'), + barBackground: 'rgba(0, 0, 0, 0.04)', + background: { + type: BackgroundType.color, + color: '#fff', + overlay: { + enabled: false, + color: 'rgba(255,255,255,0.72)', + blur: 3 + } + } +}; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss index 441391d95a..fbf244a383 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.scss @@ -20,7 +20,7 @@ display: flex; flex-direction: column; gap: 16px; - padding: 24px; + padding: 20px 24px 24px 24px; &.tb-battery-level-pointer { cursor: pointer; } @@ -34,6 +34,9 @@ bottom: 12px; right: 12px; } + div.tb-widget-title { + padding: 0; + } .tb-battery-level-content { min-height: 0; flex: 1; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts index 9161764223..a2793234f4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts @@ -263,6 +263,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView if (this.autoScaleValueSize) { const valueFontSize = ratios.valueFontSizeRatio * boxSize; const valueLineHeight = ratios.valueLineHeightRaio * boxSize; + this.renderer.setStyle(this.batteryLevelValue.nativeElement, 'minWidth', '0'); this.setValueFontSize(valueFontSize, valueLineHeight, boxWidth); } const fontSize = parseInt(window.getComputedStyle(this.batteryLevelValue.nativeElement).fontSize, 10) || 10; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.html new file mode 100644 index 0000000000..bb7089991d --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.html @@ -0,0 +1,94 @@ + + +
+
widgets.progress-bar.progress-bar-card-style
+ + + {{ progressBarLayoutTranslationMap.get(layout) | translate }} + + +
+ + {{ 'widgets.progress-bar.auto-scale' | translate }} + +
+
+ + {{ 'widgets.progress-bar.value' | translate }} + +
+ + + + +
+
+
+
{{ 'widgets.progress-bar.range' | translate }}
+
+
widgets.progress-bar.min
+ + + +
widgets.progress-bar.max
+ + + +
+
+
+ + {{ 'widgets.progress-bar.range-ticks' | translate }} + +
+ + + + +
+
+
+
{{ 'widgets.progress-bar.bar-color' | translate }}
+ + +
+
+
{{ 'widgets.progress-bar.bar-background' | translate }}
+ + +
+
+
{{ 'widgets.background.background' | translate }}
+ + +
+
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.ts new file mode 100644 index 0000000000..b56d8bff3b --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/cards/progress-bar-widget-settings.component.ts @@ -0,0 +1,133 @@ +/// +/// Copyright © 2016-2023 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, Injector } from '@angular/core'; +import { WidgetSettings, WidgetSettingsComponent } from '@shared/models/widget.models'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Store } from '@ngrx/store'; +import { AppState } from '@core/core.state'; +import { formatValue } from '@core/utils'; +import { + progressBarDefaultSettings, + ProgressBarLayout, + progressBarLayoutImages, + progressBarLayouts, + progressBarLayoutTranslations +} from '@home/components/widget/lib/cards/progress-bar-widget.models'; + +@Component({ + selector: 'tb-progress-bar-widget-settings', + templateUrl: './progress-bar-widget-settings.component.html', + styleUrls: [] +}) +export class ProgressBarWidgetSettingsComponent extends WidgetSettingsComponent { + + progressBarLayout = ProgressBarLayout; + + progressBarLayouts = progressBarLayouts; + + progressBarLayoutTranslationMap = progressBarLayoutTranslations; + progressBarLayoutImageMap = progressBarLayoutImages; + + progressBarWidgetSettingsForm: UntypedFormGroup; + + valuePreviewFn = this._valuePreviewFn.bind(this); + + constructor(protected store: Store, + private $injector: Injector, + private fb: UntypedFormBuilder) { + super(store); + } + + protected settingsForm(): UntypedFormGroup { + return this.progressBarWidgetSettingsForm; + } + + protected defaultSettings(): WidgetSettings { + return {...progressBarDefaultSettings}; + } + + protected onSettingsSet(settings: WidgetSettings) { + this.progressBarWidgetSettingsForm = this.fb.group({ + layout: [settings.layout, []], + autoScale: [settings.autoScale, []], + + showValue: [settings.showValue, []], + valueFont: [settings.valueFont, []], + valueColor: [settings.valueColor, []], + + tickMin: [settings.tickMin, []], + tickMax: [settings.tickMax, []], + + showTicks: [settings.showTicks, []], + ticksFont: [settings.ticksFont, []], + ticksColor: [settings.ticksColor, []], + + barColor: [settings.barColor, []], + barBackground: [settings.barBackground, []], + + background: [settings.background, []] + }); + } + + protected validatorTriggers(): string[] { + return ['showValue', 'showTicks', 'layout']; + } + + protected updateValidators(emitEvent: boolean) { + const showValue: boolean = this.progressBarWidgetSettingsForm.get('showValue').value; + const showTicks: boolean = this.progressBarWidgetSettingsForm.get('showTicks').value; + const layout: ProgressBarLayout = this.progressBarWidgetSettingsForm.get('layout').value; + + const ticksEnabled = layout === ProgressBarLayout.default; + + if (showValue) { + this.progressBarWidgetSettingsForm.get('valueFont').enable(); + this.progressBarWidgetSettingsForm.get('valueColor').enable(); + } else { + this.progressBarWidgetSettingsForm.get('valueFont').disable(); + this.progressBarWidgetSettingsForm.get('valueColor').disable(); + } + + if (ticksEnabled) { + this.progressBarWidgetSettingsForm.get('showTicks').enable({emitEvent: false}); + if (showTicks) { + this.progressBarWidgetSettingsForm.get('ticksFont').enable(); + this.progressBarWidgetSettingsForm.get('ticksColor').enable(); + } else { + this.progressBarWidgetSettingsForm.get('ticksFont').disable(); + this.progressBarWidgetSettingsForm.get('ticksColor').disable(); + } + } else { + this.progressBarWidgetSettingsForm.get('showTicks').disable({emitEvent: false}); + this.progressBarWidgetSettingsForm.get('ticksFont').disable(); + this.progressBarWidgetSettingsForm.get('ticksColor').disable(); + } + + this.progressBarWidgetSettingsForm.get('valueFont').updateValueAndValidity({emitEvent}); + this.progressBarWidgetSettingsForm.get('valueColor').updateValueAndValidity({emitEvent}); + this.progressBarWidgetSettingsForm.get('showTicks').updateValueAndValidity({emitEvent: false}); + this.progressBarWidgetSettingsForm.get('ticksFont').updateValueAndValidity({emitEvent}); + this.progressBarWidgetSettingsForm.get('ticksColor').updateValueAndValidity({emitEvent}); + } + + private _valuePreviewFn(): string { + const units: string = this.widgetConfig.config.units; + const decimals: number = this.widgetConfig.config.decimals; + return formatValue(78, decimals, units, true); + } + +} diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts index c4d2a1edc5..33b4323fdf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/widget-settings.module.ts @@ -297,6 +297,9 @@ import { import { ValueChartCardWidgetSettingsComponent } from '@home/components/widget/lib/settings/cards/value-chart-card-widget-settings.component'; +import { + ProgressBarWidgetSettingsComponent +} from '@home/components/widget/lib/settings/cards/progress-bar-widget-settings.component'; @NgModule({ declarations: [ @@ -406,7 +409,8 @@ import { BatteryLevelWidgetSettingsComponent, WindSpeedDirectionWidgetSettingsComponent, SignalStrengthWidgetSettingsComponent, - ValueChartCardWidgetSettingsComponent + ValueChartCardWidgetSettingsComponent, + ProgressBarWidgetSettingsComponent ], imports: [ CommonModule, @@ -521,7 +525,8 @@ import { BatteryLevelWidgetSettingsComponent, WindSpeedDirectionWidgetSettingsComponent, SignalStrengthWidgetSettingsComponent, - ValueChartCardWidgetSettingsComponent + ValueChartCardWidgetSettingsComponent, + ProgressBarWidgetSettingsComponent ] }) export class WidgetSettingsModule { @@ -601,5 +606,6 @@ export const widgetSettingsComponentsMap: {[key: string]: Type + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/assets/widget/progress-bar/simplified-layout.svg b/ui-ngx/src/assets/widget/progress-bar/simplified-layout.svg new file mode 100644 index 0000000000..2e5f60f77c --- /dev/null +++ b/ui-ngx/src/assets/widget/progress-bar/simplified-layout.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ui-ngx/src/form.scss b/ui-ngx/src/form.scss index 82794cbbc5..93272af3ca 100644 --- a/ui-ngx/src/form.scss +++ b/ui-ngx/src/form.scss @@ -225,6 +225,13 @@ margin-left: 12px; } } + .tb-small-label { + height: 40px; + font-size: 14px; + line-height: 40px; + letter-spacing: 0.2px; + color: rgba(0, 0, 0, 0.38); + } } .tb-form-row:not(.tb-standard-fields) .mat-mdc-form-field:not(.tb-not-inline-field), .mat-mdc-form-field.tb-inline-field { From 7ccad683abae4fb6cbe2454e397369b5573006ed Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 17 Oct 2023 18:41:22 +0300 Subject: [PATCH 190/267] prettify script --- application/src/main/data/upgrade/3.6.0/schema_update.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/upgrade/3.6.0/schema_update.sql b/application/src/main/data/upgrade/3.6.0/schema_update.sql index ee1b311de2..0361a5db65 100644 --- a/application/src/main/data/upgrade/3.6.0/schema_update.sql +++ b/application/src/main/data/upgrade/3.6.0/schema_update.sql @@ -29,5 +29,5 @@ CREATE INDEX IF NOT EXISTS idx_notification_request_tenant_id ON notification_re DELETE FROM widgets_bundle_widget wbw WHERE (SELECT tenant_id FROM widgets_bundle wb WHERE wb.id = wbw.widgets_bundle_id) != - (SELECT tenant_id FROM widget_type WHERE id = wbw.widget_type_id); + (SELECT tenant_id FROM widget_type wt WHERE wt.id = wbw.widget_type_id); From 04cfa2021dcc989d6130a43334a435dfaeb2f0d9 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Tue, 17 Oct 2023 18:50:42 +0300 Subject: [PATCH 191/267] Fixed edge controller tests --- .../edge/rpc/processor/BaseEdgeProcessor.java | 3 ++- .../server/controller/EdgeControllerTest.java | 11 +++++++++-- .../server/controller/EdgeEventControllerTest.java | 13 ++++++++++--- 3 files changed, 21 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java index 2d86c1e184..a888ddc27b 100644 --- a/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/edge/rpc/processor/BaseEdgeProcessor.java @@ -309,7 +309,8 @@ public abstract class BaseEdgeProcessor { EdgeEventActionType action, EntityId entityId, JsonNode body) { - ListenableFuture> future = attributesService.find(tenantId, edgeId, DataConstants.SERVER_SCOPE, DefaultDeviceStateService.ACTIVITY_STATE); + ListenableFuture> future = + attributesService.find(tenantId, edgeId, DataConstants.SERVER_SCOPE, DefaultDeviceStateService.ACTIVITY_STATE); return Futures.transformAsync(future, activeOpt -> { if (activeOpt.isEmpty()) { log.trace("Edge is not activated. Skipping event. tenantId [{}], edgeId [{}], type[{}], " + diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java index 1afeaff0cb..b9e0b8cd6c 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeControllerTest.java @@ -17,6 +17,7 @@ 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.node.ObjectNode; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListeningExecutorService; @@ -34,8 +35,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Primary; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; +import org.thingsboard.common.util.JacksonUtil; import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.common.data.Customer; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.EntitySubtype; import org.thingsboard.server.common.data.StringUtils; @@ -852,6 +855,11 @@ public class EdgeControllerTest extends AbstractControllerTest { Edge edge = doPost("/api/edge", constructEdge("Test Sync Edge", "test"), Edge.class); + // simulate edge activation + ObjectNode attributes = JacksonUtil.newObjectNode(); + attributes.put("active", true); + doPost("/api/plugins/telemetry/EDGE/" + edge.getId() + "/attributes/" + DataConstants.SERVER_SCOPE, attributes); + doPost("/api/edge/" + edge.getId().getId().toString() + "/device/" + savedDevice.getId().getId().toString(), Device.class); doPost("/api/edge/" + edge.getId().getId().toString() @@ -860,13 +868,12 @@ public class EdgeControllerTest extends AbstractControllerTest { EdgeImitator edgeImitator = new EdgeImitator(EDGE_HOST, EDGE_PORT, edge.getRoutingKey(), edge.getSecret()); edgeImitator.ignoreType(UserCredentialsUpdateMsg.class); - edgeImitator.expectMessageAmount(25); + edgeImitator.expectMessageAmount(24); edgeImitator.connect(); assertThat(edgeImitator.waitForMessages()).as("await for messages on first connect").isTrue(); verifyFetchersMsgs(edgeImitator); // verify queue msgs - Assert.assertTrue(popRuleChainMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_UPDATED_RPC_MESSAGE, "Edge Root Rule Chain")); Assert.assertTrue(popDeviceProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "default")); Assert.assertTrue(popDeviceMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "Test Sync Edge Device 1")); Assert.assertTrue(popAssetProfileMsg(edgeImitator.getDownlinkMsgs(), UpdateMsgType.ENTITY_CREATED_RPC_MESSAGE, "test")); diff --git a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java index 04842df6a0..3303c64c27 100644 --- a/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/EdgeEventControllerTest.java @@ -16,6 +16,7 @@ package org.thingsboard.server.controller; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.node.ObjectNode; import lombok.extern.slf4j.Slf4j; import org.awaitility.Awaitility; import org.junit.After; @@ -26,6 +27,8 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.test.context.TestPropertySource; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.asset.Asset; import org.thingsboard.server.common.data.edge.Edge; @@ -86,6 +89,11 @@ public class EdgeEventControllerTest extends AbstractControllerTest { Edge edge = constructEdge("TestEdge", "default"); edge = doPost("/api/edge", edge, Edge.class); + // simulate edge activation + ObjectNode attributes = JacksonUtil.newObjectNode(); + attributes.put("active", true); + doPost("/api/plugins/telemetry/EDGE/" + edge.getId() + "/attributes/" + DataConstants.SERVER_SCOPE, attributes); + Device device = constructDevice("TestDevice", "default"); Device savedDevice = doPost("/api/device", device, Device.class); @@ -99,14 +107,13 @@ public class EdgeEventControllerTest extends AbstractControllerTest { EntityRelation relation = new EntityRelation(savedAsset.getId(), savedDevice.getId(), EntityRelation.CONTAINS_TYPE); - awaitForNumberOfEdgeEvents(edgeId, 3); + awaitForNumberOfEdgeEvents(edgeId, 2); doPost("/api/relation", relation); - awaitForNumberOfEdgeEvents(edgeId, 4); + awaitForNumberOfEdgeEvents(edgeId, 3); List edgeEvents = findEdgeEvents(edgeId); - Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RULE_CHAIN)); // root rule chain Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.DEVICE)); // TestDevice Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.ASSET)); // TestAsset Assert.assertTrue(popEdgeEvent(edgeEvents, EdgeEventType.RELATION)); From cf32544e71f7dd3bd43059fd2b4328c1a3747dc2 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 17 Oct 2023 23:20:00 +0200 Subject: [PATCH 192/267] added SslUtil and tests --- common/util/pom.xml | 8 ++ .../org/thingsboard/common/util/SslUtil.java | 105 ++++++++++++++++++ .../credentials/CertPemCredentials.java | 82 ++------------ .../credentials/CertPemCredentialsTest.java | 51 ++++++--- .../src/test/resources/pem/ec_cert.pem | 13 +++ .../src/test/resources/pem/rsa_cert.pem | 32 ++++++ .../test/resources/pem/rsa_encrypted_cert.pem | 22 ++++ .../pem/rsa_encrypted_traditional_cert.pem | 22 ++++ 8 files changed, 245 insertions(+), 90 deletions(-) create mode 100644 common/util/src/main/java/org/thingsboard/common/util/SslUtil.java create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem create mode 100644 rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem diff --git a/common/util/pom.xml b/common/util/pom.xml index 14ae1748b2..bce6a6fc80 100644 --- a/common/util/pom.xml +++ b/common/util/pom.xml @@ -36,6 +36,14 @@ + + org.bouncycastle + bcprov-jdk15on + + + org.bouncycastle + bcpkix-jdk15on + org.springframework spring-core diff --git a/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java new file mode 100644 index 0000000000..889436671a --- /dev/null +++ b/common/util/src/main/java/org/thingsboard/common/util/SslUtil.java @@ -0,0 +1,105 @@ +/** + * Copyright © 2016-2023 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 lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; +import org.bouncycastle.cert.X509CertificateHolder; +import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; +import org.bouncycastle.jce.provider.BouncyCastleProvider; +import org.bouncycastle.openssl.PEMDecryptorProvider; +import org.bouncycastle.openssl.PEMEncryptedKeyPair; +import org.bouncycastle.openssl.PEMKeyPair; +import org.bouncycastle.openssl.PEMParser; +import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; +import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; +import org.bouncycastle.operator.InputDecryptorProvider; +import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; +import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; +import org.thingsboard.server.common.data.StringUtils; + +import java.io.StringReader; +import java.security.PrivateKey; +import java.security.Security; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.List; + +@Slf4j +public class SslUtil { + + public static final char[] EMPTY_PASS = {}; + + public static final BouncyCastleProvider DEFAULT_PROVIDER = new BouncyCastleProvider(); + + static { + if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { + Security.addProvider(DEFAULT_PROVIDER); + } + } + + private SslUtil() { + } + + @SneakyThrows + public static List readCertFile(String fileContent) { + List certificates = new ArrayList<>(); + JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof X509CertificateHolder) { + X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object); + certificates.add(x509Cert); + } + } + } + return certificates; + } + + @SneakyThrows + public static PrivateKey readPrivateKey(String fileContent, String passStr) { + char[] password = StringUtils.isEmpty(passStr) ? EMPTY_PASS : passStr.toCharArray(); + + PrivateKey privateKey = null; + JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); + if (StringUtils.isNotEmpty(fileContent)) { + try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { + Object object; + while ((object = pemParser.readObject()) != null) { + if (object instanceof PEMEncryptedKeyPair) { + PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password); + privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); + break; + } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { + InputDecryptorProvider decProv = + new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(DEFAULT_PROVIDER).build(password); + privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); + break; + } else if (object instanceof PEMKeyPair) { + privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); + break; + } else if (object instanceof PrivateKeyInfo) { + privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); + } + } + } + } + return privateKey; + } + +} diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java index c17f71bc33..3824e71459 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/credentials/CertPemCredentials.java @@ -20,35 +20,17 @@ import io.netty.handler.ssl.SslContext; import io.netty.handler.ssl.SslContextBuilder; import lombok.Data; import lombok.extern.slf4j.Slf4j; -import org.bouncycastle.asn1.pkcs.PrivateKeyInfo; -import org.bouncycastle.cert.X509CertificateHolder; -import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter; -import org.bouncycastle.jce.provider.BouncyCastleProvider; -import org.bouncycastle.openssl.PEMDecryptorProvider; -import org.bouncycastle.openssl.PEMEncryptedKeyPair; -import org.bouncycastle.openssl.PEMKeyPair; -import org.bouncycastle.openssl.PEMParser; -import org.bouncycastle.openssl.jcajce.JcaPEMKeyConverter; -import org.bouncycastle.openssl.jcajce.JcePEMDecryptorProviderBuilder; -import org.bouncycastle.operator.InputDecryptorProvider; -import org.bouncycastle.pkcs.PKCS8EncryptedPrivateKeyInfo; -import org.bouncycastle.pkcs.PKCSException; -import org.bouncycastle.pkcs.jcajce.JcePKCSPBEInputDecryptorProviderBuilder; +import org.thingsboard.common.util.SslUtil; import org.thingsboard.server.common.data.StringUtils; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; -import java.io.IOException; -import java.io.StringReader; -import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.PrivateKey; -import java.security.Security; import java.security.cert.CertPath; import java.security.cert.Certificate; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; -import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; @@ -61,16 +43,11 @@ public class CertPemCredentials implements ClientCredentials { public static final String X_509 = "X.509"; public static final String CERT_ALIAS_PREFIX = "cert-"; public static final String CA_CERT_CERT_ALIAS_PREFIX = "caCert-cert-"; + protected String caCert; private String cert; private String privateKey; - private String password; - - public CertPemCredentials() { - if (Security.getProvider(BouncyCastleProvider.PROVIDER_NAME) == null) { - Security.addProvider(new BouncyCastleProvider()); - } - } + private String password = ""; @Override public CredentialsType getType() { @@ -95,7 +72,7 @@ public class CertPemCredentials implements ClientCredentials { } protected TrustManagerFactory createAndInitTrustManagerFactory() throws Exception { - List caCerts = readCertFile(caCert); + List caCerts = SslUtil.readCertFile(caCert); KeyStore caKeyStore = KeyStore.getInstance(KeyStore.getDefaultType()); caKeyStore.load(null, null); @@ -108,15 +85,15 @@ public class CertPemCredentials implements ClientCredentials { return trustManagerFactory; } - protected KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { + private KeyManagerFactory createAndInitKeyManagerFactory() throws Exception { KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); kmf.init(loadKeyStore(), password.toCharArray()); return kmf; } - private KeyStore loadKeyStore() throws Exception { - List certificates = readCertFile(this.cert); - PrivateKey privateKey = readPrivateKey(this.privateKey, this.password); + protected KeyStore loadKeyStore() throws Exception { + List certificates = SslUtil.readCertFile(this.cert); + PrivateKey privateKey = SslUtil.readPrivateKey(this.privateKey, password); KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); keyStore.load(null); @@ -135,47 +112,4 @@ public class CertPemCredentials implements ClientCredentials { return keyStore; } - protected List readCertFile(String fileContent) throws IOException, GeneralSecurityException { - List certificates = new ArrayList<>(); - JcaX509CertificateConverter certConverter = new JcaX509CertificateConverter(); - try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { - Object object; - while ((object = pemParser.readObject()) != null) { - if (object instanceof X509CertificateHolder) { - X509Certificate x509Cert = certConverter.getCertificate((X509CertificateHolder) object); - certificates.add(x509Cert); - } - } - } - return certificates; - } - - protected PrivateKey readPrivateKey(String fileContent, String password) throws IOException, PKCSException { - PrivateKey privateKey = null; - JcaPEMKeyConverter keyConverter = new JcaPEMKeyConverter(); - - if (StringUtils.isNotEmpty(fileContent)) { - try (PEMParser pemParser = new PEMParser(new StringReader(fileContent))) { - Object object; - while ((object = pemParser.readObject()) != null) { - if (object instanceof PEMEncryptedKeyPair) { - PEMDecryptorProvider decProv = new JcePEMDecryptorProviderBuilder().build(password.toCharArray()); - privateKey = keyConverter.getKeyPair(((PEMEncryptedKeyPair) object).decryptKeyPair(decProv)).getPrivate(); - break; - } else if (object instanceof PKCS8EncryptedPrivateKeyInfo) { - InputDecryptorProvider decProv = - new JcePKCSPBEInputDecryptorProviderBuilder().setProvider(new BouncyCastleProvider()).build(password.toCharArray()); - privateKey = keyConverter.getPrivateKey(((PKCS8EncryptedPrivateKeyInfo) object).decryptPrivateKeyInfo(decProv)); - break; - } else if (object instanceof PEMKeyPair) { - privateKey = keyConverter.getKeyPair((PEMKeyPair) object).getPrivate(); - break; - } else if (object instanceof PrivateKeyInfo) { - privateKey = keyConverter.getPrivateKey((PrivateKeyInfo) object); - } - } - } - } - return privateKey; - } } diff --git a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java index fd7f0d3378..2cecd1490d 100644 --- a/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java +++ b/rule-engine/rule-engine-components/src/test/java/org/thingsboard/rule/engine/credentials/CertPemCredentialsTest.java @@ -22,28 +22,32 @@ import org.junit.jupiter.api.Assertions; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; +import org.thingsboard.common.util.SslUtil; import java.io.File; import java.io.IOException; -import java.security.PrivateKey; +import java.security.Key; +import java.security.KeyStore; +import java.security.cert.Certificate; import java.security.cert.X509Certificate; import java.util.List; import java.util.stream.Stream; -public class CertPemCredentialsTest { +import static org.thingsboard.rule.engine.credentials.CertPemCredentials.CERT_ALIAS_PREFIX; +import static org.thingsboard.rule.engine.credentials.CertPemCredentials.PRIVATE_KEY_ALIAS; - private final CertPemCredentials credentials = new CertPemCredentials(); +public class CertPemCredentialsTest { private static final String PASS = "test"; private static final String EMPTY_PASS = ""; private static final String RSA = "RSA"; - private static final String ECDSA = "ECDSA"; + private static final String EC = "EC"; @Test public void testChainOfCertificates() throws Exception { String fileContent = fileContent("pem/tb-cloud-chain.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(4, x509Certificates.size()); Assert.assertEquals("CN=*.thingsboard.cloud, O=\"ThingsBoard, Inc.\", ST=New York, C=US", @@ -60,7 +64,7 @@ public class CertPemCredentialsTest { public void testSingleCertificate() throws Exception { String fileContent = fileContent("pem/tb-cloud.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(1, x509Certificates.size()); Assert.assertEquals("CN=*.thingsboard.cloud, O=\"ThingsBoard, Inc.\", ST=New York, C=US", @@ -71,26 +75,41 @@ public class CertPemCredentialsTest { public void testEmptyFileContent() throws Exception { String fileContent = fileContent("pem/empty.pem"); - List x509Certificates = credentials.readCertFile(fileContent); + List x509Certificates = SslUtil.readCertFile(fileContent); Assert.assertEquals(0, x509Certificates.size()); } - private static Stream testReadPrivateKey() { + private static Stream testLoadKeyStore() { return Stream.of( - Arguments.of("pem/rsa_key.pem", EMPTY_PASS, RSA), - Arguments.of("pem/rsa_encrypted_key.pem", PASS, RSA), - Arguments.of("pem/rsa_encrypted_traditional_key.pem", PASS, RSA), - Arguments.of("pem/ec_key.pem", EMPTY_PASS, ECDSA) + Arguments.of("pem/rsa_cert.pem", "pem/rsa_key.pem", EMPTY_PASS, RSA), + Arguments.of("pem/rsa_encrypted_cert.pem", "pem/rsa_encrypted_key.pem", PASS, RSA), + Arguments.of("pem/rsa_encrypted_traditional_cert.pem", "pem/rsa_encrypted_traditional_key.pem", PASS, RSA), + Arguments.of("pem/ec_cert.pem", "pem/ec_key.pem", EMPTY_PASS, EC) ); } @ParameterizedTest @MethodSource - public void testReadPrivateKey(String keyPath, String password, String algorithm) throws Exception { - PrivateKey privateKey = credentials.readPrivateKey(fileContent(keyPath), password); - Assertions.assertNotNull(privateKey); - Assertions.assertEquals(algorithm, privateKey.getAlgorithm()); + public void testLoadKeyStore(String certPath, String keyPath, String password, String algorithm) throws Exception { + CertPemCredentials certPemCredentials = new CertPemCredentials(); + String certContent = fileContent(certPath); + certPemCredentials.setCert(certContent); + certPemCredentials.setPrivateKey(fileContent(keyPath)); + certPemCredentials.setPassword(password); + KeyStore keyStore = certPemCredentials.loadKeyStore(); + Assertions.assertNotNull(keyStore); + Key key = keyStore.getKey(PRIVATE_KEY_ALIAS, password.toCharArray()); + Assertions.assertNotNull(key); + Assertions.assertEquals(algorithm, key.getAlgorithm()); + + List certs = SslUtil.readCertFile(certContent); + for (X509Certificate cert : certs) { + String alias = CERT_ALIAS_PREFIX + cert.getIssuerDN().getName(); + Certificate certificate = keyStore.getCertificate(alias); + Assertions.assertNotNull(certificate); + Assertions.assertEquals(new String(cert.getEncoded()), new String(certificate.getEncoded())); + } } private String fileContent(String fileName) throws IOException { diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem new file mode 100644 index 0000000000..f22f61d3a1 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/ec_cert.pem @@ -0,0 +1,13 @@ +-----BEGIN CERTIFICATE----- +MIICCDCCAa2gAwIBAgIUGx/SZqIWza/i/gaKFUVIyTEu2oMwCgYIKoZIzj0EAwIw +WTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJ +BgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIz +MTAxNjEyMjMyMVoXDTI0MTAxNTEyMjMyMVowWTELMAkGA1UEBhMCVUExDTALBgNV +BAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQLDAJU +QjESMBAGA1UEAwwJbG9jYWxob3N0MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +z4MgawieJfVc5zUOPiw5WFxfHGJf7dOMsHvudDxdOs27PXPbJfi09BVJ3+JjNxA2 +wQz9KUk877oWRYrN/e+MbKNTMFEwHQYDVR0OBBYEFDTV8VD3m+8IBQOBJ+V/bcbl +4preMB8GA1UdIwQYMBaAFDTV8VD3m+8IBQOBJ+V/bcbl4preMA8GA1UdEwEB/wQF +MAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAOgIkl8j8m51W7pWlNUAuUnHnOVhVjGr +h8Rc6cbwTapKAiEA2CLrduTweXEF5fBRtWyOsG8c9af6+MWHKmwHL1IDw9Q= +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem new file mode 100644 index 0000000000..f89fce7444 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_cert.pem @@ -0,0 +1,32 @@ +-----BEGIN CERTIFICATE----- +MIIFkzCCA3ugAwIBAgIUUQa3cWUVoF58dzg8ycb/y7SdCj8wDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxMzEyMzcwMVoXDTI0MTAxMjEyMzcwMVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIICIjANBgkqhkiG9w0BAQEFAAOCAg8A +MIICCgKCAgEAsHn27cH+pYFI0eJYer8ww29g/xlKgr9aarYlkILeXnBhPPHBCXG+ +FegeMpHa8FUPANIqYJiwM13altO6hMLPa0J7+nQhwF5NCbxzAdi/kU8ofhIwJH+K +gOsD3BKdR7Ua7KMDQFnGTFRR9ZxsuYZ/0AHuzPHwxSLUvvMbiWbu5P2FYMrEyyLo +uVVihZPkeBhcnI6SJRyCdMdMy282nWQ+47gAUI3cFa7dXxUcXvRbbToMNPTIDUy4 +VhxJYhL4T6ED0Ds7tZRsG71LcMfw2RQUgiS1FuYh+O7N8lUMukMy2/umQluM0+qB +CYWa2p1UCbVzlrW1qgKQm1Q8E91XSR9KL/zdO8m9/uNeI1jyJu6i1cibWR7gnh6J +ChLxouQlrBzuLzSz7PG8q1MOWi+oHYJWSvmsckbQDhwEsfhFrYVgndJdxnmlkzvS +1OP7RGSYXLfMF+ZxC2YEJiU65QACCl2IHknyNiL8Jg5ahXgZMNshyfvOv5RB5jnz +4vzRpGhUYCcyLzORT+5gY9ZYbX/51cOomQV1ryTTQs+zA8mfEVLjbbLqvYdI84LC +3chMdcOm8Z9U1xdb2FX/c724XDyPnQNy1PLggzqvOFZzLeey0nBVUWyVrcCydbS5 +PAvVoAucO8kqP6b7uB7QnDeGaCiAVF+9QaXxjyQEdLEu3z5JMM7uH4UCAwEAAaNT +MFEwHQYDVR0OBBYEFHXrT3L+O3kJ2xNZ4Lh1ThGG6M1vMB8GA1UdIwQYMBaAFHXr +T3L+O3kJ2xNZ4Lh1ThGG6M1vMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggIBABFDqkTdxsJyu5L2x3WSpw4jw4vgJYlgUvTSeU8i54DaSzncLZdpWsqb +37LFHkvlquIfvOi9f9EBT2KuZwaajPQBNE4m7kLchoAv8Mc8a2EXhN2caXamnN3F +vWAb4QW/VHKKz2vWprfARwqQO58TEPgzU4FcW1lPpX2ULBeoS5kZDDEgyfaFZETF +FnsSb9E3/YuH6sJCu880kbW8BIyQmbUytrbn+16J/iaZBwc+iD49t2VBLDOsr1x4 +5qzxknG3h9wiz9ob9v6hWFfMpdiK12S0P5FVsUkCpxoae8jc8rPS7W3HaYowFjVR +OHOjtWy5/SV2rypKShjg9manf6iwGdTGkD0qoqsRs9JQFabjNR23IQv+1OUbrEVC +DbS65IjwLJlIZBX8JuJaU3I8zqj/9q7TtRDp1NCiG5W0NgipERRCciWaLJ+Fz6Lu +QzhI2ZOJrl49hmr6e0bsyNUv9l89WcbKm3/IC+V7o80uADYCOaz2jDGfKbvcPHzN +mTma8qVsjpcedttsvNMyZOsM/Rpk+dbChgReRVvcmzQV0izEvJJBWFr4HrfcM6Ev +sZrnUiT8ENUZqiK40d+T3Q6JheHwm+ENI1aUDkYCpoWZ/PzKe+Bj8lR8dPvmeVrc +eiwS37nMFO/5X7aIkszTouScNO99cN0UqPldfJo+8ZTbai5VFxGD +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem new file mode 100644 index 0000000000..2f4e55a612 --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUKAylzm/K5OfbXSjm1zY9bX1a8HQwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxNjIxMDQwNVoXDTI0MTAxNTIxMDQwNVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA87nLliszEWml8QvyAC+H80NZCxf4TcG826NBOp0AUPJ8xQBHCzc1 +t1ohVm2/fn2VJZAYXG2xSVcHyXjjjv3iGLE2AIDbXh06/yFg4TVjlbrWrAHFehyN +FwrK8ez36oGLa3ZVq+mx1fLfBQw5mStbh09NXmKTzqP6m9ggKtt63cUwoWdUTemT +qrjryJd69LiJi+MVqtbKO2j30/lgAZmaHtbojl9EcvWfeXLb20TnXRIctaIS1VGo +SluzjbNQErdN/VRW4RAOP6UFsK0xID2EuLODBmAWnI49fXO/OS+u3Kd3suABE0o9 +slfDXqNTp0r5N0OoSAFcc4EsV3+9Gf+mqwIDAQABo1MwUTAdBgNVHQ4EFgQUhS5K +XQDxGvaBCpKY1de+JZl8zjYwHwYDVR0jBBgwFoAUhS5KXQDxGvaBCpKY1de+JZl8 +zjYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAxez4vLtBCBNM +l6AQghViNAR9iiwYMxUwKwlU+uZftRGnT+6dXgfTR3PV6LCfMMmtuNs0JTGy0ff8 +erbzfZxExvHfIFXCwepwTWawQhvRRn9GHOJXIzESDRRhsXoJDzd0JVOx0wWxp1cz +EUts+ZbKLoC+kIhsOGY+0a+sopeV2rMO5bUMpA8P0mKZlGynEGMLzKxz65E/IA9h +EQKpJjpvYfN+7eUkF6ZRXNV2LI/8BCoG6mOVoOMEXnloPwwBtOevoCB43U3sT9Er +WQWgZdbeI4gEyEqgMTibNogZZF0KW+5as3iv7avDd8pCgONvD0iwKSlvi9RNjiw8 +p6bwNmBcuA== +-----END CERTIFICATE----- diff --git a/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem new file mode 100644 index 0000000000..38ab2e42fe --- /dev/null +++ b/rule-engine/rule-engine-components/src/test/resources/pem/rsa_encrypted_traditional_cert.pem @@ -0,0 +1,22 @@ +-----BEGIN CERTIFICATE----- +MIIDkzCCAnugAwIBAgIUIo+5l07ZrQR/LxEEmUbnn4yxCwIwDQYJKoZIhvcNAQEL +BQAwWTELMAkGA1UEBhMCVUExDTALBgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYx +CzAJBgNVBAoMAlRCMQswCQYDVQQLDAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MB4X +DTIzMTAxNjIxMDMxNVoXDTI0MTAxNTIxMDMxNVowWTELMAkGA1UEBhMCVUExDTAL +BgNVBAgMBEtZSVYxDTALBgNVBAcMBEtZSVYxCzAJBgNVBAoMAlRCMQswCQYDVQQL +DAJUQjESMBAGA1UEAwwJbG9jYWxob3N0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A +MIIBCgKCAQEA87nLliszEWml8QvyAC+H80NZCxf4TcG826NBOp0AUPJ8xQBHCzc1 +t1ohVm2/fn2VJZAYXG2xSVcHyXjjjv3iGLE2AIDbXh06/yFg4TVjlbrWrAHFehyN +FwrK8ez36oGLa3ZVq+mx1fLfBQw5mStbh09NXmKTzqP6m9ggKtt63cUwoWdUTemT +qrjryJd69LiJi+MVqtbKO2j30/lgAZmaHtbojl9EcvWfeXLb20TnXRIctaIS1VGo +SluzjbNQErdN/VRW4RAOP6UFsK0xID2EuLODBmAWnI49fXO/OS+u3Kd3suABE0o9 +slfDXqNTp0r5N0OoSAFcc4EsV3+9Gf+mqwIDAQABo1MwUTAdBgNVHQ4EFgQUhS5K +XQDxGvaBCpKY1de+JZl8zjYwHwYDVR0jBBgwFoAUhS5KXQDxGvaBCpKY1de+JZl8 +zjYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAiUTgjnsVIg90 +Dm+XSlscIPbZEj/mJanoFFfAfbVJz1DadygG9viVUMf3jVQBcsJGeBDckR2b3OHY +82cQVpdu3Heqld+gnfsyi8QBi7EdK4i0q8NVqFgpw83KxNm9xt7xrgHtxhE0kWfW +dpTgeIu0hFf0qLUObw/g8+0awBuxNY2crLtLXQM/dRgtv5Zt/DilW3jMLAE5wke+ +/HM4/emOJO6DSI9BC8iUsmNpIpq45267jcjpczNBo3ap7Bad+jM/paRDng9Uavvr +VCsaJFaL5HG6TtNXN60npBouOWnivPzUeuTI4PnjGRgdp3lgb0IuXbuwxIW6FVG/ +73RHc0gGOA== +-----END CERTIFICATE----- From c5c037b874a32519c79490e7d1f75ad8e832dd52 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 18 Oct 2023 08:47:03 +0300 Subject: [PATCH 193/267] Update AlarmControllerTest with latest business logic - no edge notification during alarm udpate --- .../thingsboard/server/controller/AlarmControllerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java index 0e6eb16713..2f859055bd 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AlarmControllerTest.java @@ -136,7 +136,7 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(AlarmSeverity.MAJOR, updatedAlarm.getSeverity()); AlarmInfo foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, updatedAlarm.getId(), updatedAlarm.getOriginator(), + testNotifyEntityOneTimeMsgToEdgeServiceNever(foundAlarm, updatedAlarm.getId(), updatedAlarm.getOriginator(), tenantId, customerId, customerUserId, CUSTOMER_USER_EMAIL, ActionType.UPDATED); } @@ -153,7 +153,7 @@ public class AlarmControllerTest extends AbstractControllerTest { Assert.assertEquals(AlarmSeverity.MAJOR, updatedAlarm.getSeverity()); AlarmInfo foundAlarm = doGet("/api/alarm/info/" + updatedAlarm.getId(), AlarmInfo.class); - testNotifyEntityAllOneTime(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), + testNotifyEntityOneTimeMsgToEdgeServiceNever(foundAlarm, foundAlarm.getId(), foundAlarm.getOriginator(), tenantId, customerId, tenantAdminUserId, TENANT_ADMIN_EMAIL, ActionType.UPDATED); alarm = updatedAlarm; From 9b6b161d37e79506f9895c53f4abd58d5dfdeda5 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Wed, 18 Oct 2023 10:15:51 +0300 Subject: [PATCH 194/267] Revert changes for getting alarms by ids --- ui-ngx/src/app/core/http/entity.service.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/ui-ngx/src/app/core/http/entity.service.ts b/ui-ngx/src/app/core/http/entity.service.ts index cc1dd13345..b4eab83b08 100644 --- a/ui-ngx/src/app/core/http/entity.service.ts +++ b/ui-ngx/src/app/core/http/entity.service.ts @@ -240,9 +240,7 @@ export class EntityService { entityIds); break; case EntityType.ALARM: - observable = this.getEntitiesByIdsObservable( - (id) => this.alarmService.getAlarm(id, config), - entityIds); + console.error('Get Alarm Entity is not implemented!'); break; case EntityType.DEVICE_PROFILE: observable = this.getEntitiesByIdsObservable( From 6701ef46f533e5a9632d40542caf7f4fce1dd768 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 18 Oct 2023 11:00:20 +0300 Subject: [PATCH 195/267] fixed upgrade script for rule nodes --- .../update/DefaultDataUpdateService.java | 101 ++++++++++-------- .../server/dao/rule/RuleChainService.java | 4 + .../server/dao/rule/BaseRuleChainService.java | 18 ++++ .../server/dao/rule/RuleNodeDao.java | 5 + .../server/dao/sql/rule/JpaRuleNodeDao.java | 16 +++ .../dao/sql/rule/RuleNodeRepository.java | 5 + .../dao/sql/rule/JpaRuleNodeDaoTest.java | 39 ++++++- 7 files changed, 140 insertions(+), 48 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 8c3b78040b..d16b8c362b 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 @@ -17,7 +17,7 @@ package org.thingsboard.server.service.install.update; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.node.ObjectNode; -import com.google.common.collect.Iterables; +import com.google.common.collect.Lists; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; @@ -84,6 +84,7 @@ 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.service.component.ComponentDiscoveryService; +import org.thingsboard.server.service.component.RuleNodeClassInfo; import org.thingsboard.server.service.install.InstallScripts; import org.thingsboard.server.service.install.SystemDataLoaderService; @@ -102,7 +103,8 @@ import static org.thingsboard.server.common.data.StringUtils.isBlank; @Slf4j public class DefaultDataUpdateService implements DataUpdateService { - private static final int MAX_PENDING_SAVE_RULE_NODE_FUTURES = 100; + private static final int MAX_PENDING_SAVE_RULE_NODE_FUTURES = 256; + private static final int DEFAULT_PAGE_SIZE = 1024; @Autowired private TenantService tenantService; @@ -231,67 +233,77 @@ public class DefaultDataUpdateService implements DataUpdateService { @Override public void upgradeRuleNodes() { try { - var futures = new ArrayList>(100); int totalRuleNodesUpgraded = 0; log.info("Starting rule nodes upgrade ..."); var nodeClassToVersionMap = componentDiscoveryService.getVersionedNodes(); log.debug("Found {} versioned nodes to check for upgrade!", nodeClassToVersionMap.size()); for (var ruleNodeClassInfo : nodeClassToVersionMap) { - var ruleNodeType = ruleNodeClassInfo.getClassName(); var ruleNodeTypeForLogs = ruleNodeClassInfo.getSimpleName(); var toVersion = ruleNodeClassInfo.getCurrentVersion(); log.debug("Going to check for nodes with type: {} to upgrade to version: {}.", ruleNodeTypeForLogs, toVersion); - var ruleNodesToUpdate = new PageDataIterable<>( - pageLink -> ruleChainService.findAllRuleNodesByTypeAndVersionLessThan(ruleNodeType, toVersion, pageLink), 1024 - ); - if (Iterables.isEmpty(ruleNodesToUpdate)) { - log.debug("There are no active nodes with type: {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs); - } else { - for (var ruleNode : ruleNodesToUpdate) { - var ruleNodeId = ruleNode.getId(); - var oldConfiguration = ruleNode.getConfiguration(); - int fromVersion = ruleNode.getConfigurationVersion(); - log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); - try { - var tbVersionedNode = (TbNode) ruleNodeClassInfo.getClazz().getDeclaredConstructor().newInstance(); - TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration); - if (upgradeRuleNodeConfigurationResult.getFirst()) { - ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond()); - } - ruleNode.setConfigurationVersion(toVersion); - futures.add(jpaExecutorService.submit(() -> { - ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode); - log.debug("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", - ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion); - })); - if (futures.size() >= MAX_PENDING_SAVE_RULE_NODE_FUTURES) { - log.info("{} upgraded rule nodes so far ...", - totalRuleNodesUpgraded += awaitFuturesToCompleteAndGetCount(futures)); - futures.clear(); - } - } catch (Exception e) { - log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ", - ruleNodeId, ruleNodeTypeForLogs, fromVersion, toVersion, e); - } - } + var ruleNodesIdsToUpgrade = getRuleNodesIdsWithTypeAndVersionLessThan(ruleNodeClassInfo.getClassName(), toVersion); + if (ruleNodesIdsToUpgrade.isEmpty()) { + log.debug("There are no active nodes with type {}, or all nodes with this type already set to latest version!", ruleNodeTypeForLogs); + continue; + } + var ruleNodeIdsPartitions = Lists.partition(ruleNodesIdsToUpgrade, MAX_PENDING_SAVE_RULE_NODE_FUTURES); + for (var ruleNodePack : ruleNodeIdsPartitions) { + totalRuleNodesUpgraded += processRuleNodePack(ruleNodePack, ruleNodeClassInfo); + log.info("{} upgraded rule nodes so far ...", totalRuleNodesUpgraded); } } - log.info("Finished rule nodes upgrade. Upgraded rule nodes count: {}", - totalRuleNodesUpgraded + awaitFuturesToCompleteAndGetCount(futures)); + log.info("Finished rule nodes upgrade. Upgraded rule nodes count: {}", totalRuleNodesUpgraded); } catch (Exception e) { log.error("Unexpected error during rule nodes upgrade: ", e); } } - private int awaitFuturesToCompleteAndGetCount(List> futures) { + private int processRuleNodePack(List ruleNodeIdsBatch, RuleNodeClassInfo ruleNodeClassInfo) { + var saveFutures = new ArrayList>(MAX_PENDING_SAVE_RULE_NODE_FUTURES); + String ruleNodeType = ruleNodeClassInfo.getSimpleName(); + int toVersion = ruleNodeClassInfo.getCurrentVersion(); + var ruleNodesPack = ruleChainService.findAllRuleNodesByIds(ruleNodeIdsBatch); + for (var ruleNode : ruleNodesPack) { + if (ruleNode == null) { + continue; + } + var ruleNodeId = ruleNode.getId(); + var oldConfiguration = ruleNode.getConfiguration(); + int fromVersion = ruleNode.getConfigurationVersion(); + log.debug("Going to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", + ruleNodeId, ruleNodeType, fromVersion, toVersion); + try { + var tbVersionedNode = (TbNode) ruleNodeClassInfo.getClazz().getDeclaredConstructor().newInstance(); + TbPair upgradeRuleNodeConfigurationResult = tbVersionedNode.upgrade(fromVersion, oldConfiguration); + if (upgradeRuleNodeConfigurationResult.getFirst()) { + ruleNode.setConfiguration(upgradeRuleNodeConfigurationResult.getSecond()); + } + ruleNode.setConfigurationVersion(toVersion); + saveFutures.add(jpaExecutorService.submit(() -> { + ruleChainService.saveRuleNode(TenantId.SYS_TENANT_ID, ruleNode); + log.debug("Successfully upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {}", + ruleNodeId, ruleNodeType, fromVersion, toVersion); + })); + } catch (Exception e) { + log.warn("Failed to upgrade rule node with id: {} type: {} fromVersion: {} toVersion: {} due to: ", + ruleNodeId, ruleNodeType, fromVersion, toVersion, e); + } + } try { - return Futures.allAsList(futures).get().size(); + return Futures.allAsList(saveFutures).get().size(); } catch (ExecutionException | InterruptedException e) { throw new RuntimeException("Failed to process save rule nodes requests due to: ", e); } } + private List getRuleNodesIdsWithTypeAndVersionLessThan(String type, int toVersion) { + var ruleNodeIds = new ArrayList(); + new PageDataIterable<>(pageLink -> + ruleChainService.findAllRuleNodeIdsByTypeAndVersionLessThan(type, toVersion, pageLink), DEFAULT_PAGE_SIZE + ).forEach(ruleNodeIds::add); + return ruleNodeIds; + } + private final PaginatedUpdater deviceProfileEntityDynamicConditionsUpdater = new PaginatedUpdater<>() { @@ -373,12 +385,11 @@ public class DefaultDataUpdateService implements DataUpdateService { 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; + List relations = relationService.findRuleNodeToRuleChainRelations(TenantId.SYS_TENANT_ID, RuleChainType.CORE, DEFAULT_PAGE_SIZE); + hasNext = relations.size() == DEFAULT_PAGE_SIZE; for (EntityRelation relation : relations) { try { RuleNodeId sourceNodeId = new RuleNodeId(relation.getFrom().getId()); 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 95cdc0e02d..532da4ac00 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 @@ -102,6 +102,10 @@ public interface RuleChainService extends EntityDaoService { PageData findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink); + PageData findAllRuleNodeIdsByTypeAndVersionLessThan(String type, int version, PageLink pageLink); + + List findAllRuleNodesByIds(List ruleNodeIds); + RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode); void deleteRuleNodes(TenantId tenantId, RuleChainId ruleChainId); 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 5e6b1e8009..956e4b83f6 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 @@ -78,6 +78,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.validateIds; import static org.thingsboard.server.dao.service.Validator.validatePageLink; import static org.thingsboard.server.dao.service.Validator.validatePositiveNumber; import static org.thingsboard.server.dao.service.Validator.validateString; @@ -726,6 +727,23 @@ public class BaseRuleChainService extends AbstractEntityService implements RuleC return ruleNodeDao.findAllRuleNodesByTypeAndVersionLessThan(type, version, pageLink); } + @Override + public PageData findAllRuleNodeIdsByTypeAndVersionLessThan(String type, int version, PageLink pageLink) { + log.trace("Executing findAllRuleNodeIdsByTypeAndVersionLessThan, type {}, pageLink {}, version {}", type, pageLink, version); + validateString(type, "Incorrect type of the rule node"); + validatePositiveNumber(version, "Incorrect version to compare with. Version should be greater than 0!"); + validatePageLink(pageLink); + return ruleNodeDao.findAllRuleNodeIdsByTypeAndVersionLessThan(type, version, pageLink); + } + + @Override + public List findAllRuleNodesByIds(List ruleNodeIds) { + log.trace("Executing findAllRuleNodesByIds, ruleNodeIds {}", ruleNodeIds); + validateIds(ruleNodeIds, "Incorrect ruleNodeIds " + ruleNodeIds); + assert ruleNodeIds.size() <= 1024; + return ruleNodeDao.findAllRuleNodeByIds(ruleNodeIds); + } + @Override public RuleNode saveRuleNode(TenantId tenantId, RuleNode ruleNode) { return ruleNodeDao.save(tenantId, ruleNode); 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 cd8fbb0a3c..b6f2dd097e 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 @@ -36,7 +36,12 @@ public interface RuleNodeDao extends Dao { PageData findAllRuleNodesByTypeAndVersionLessThan(String type, int version, PageLink pageLink); + PageData findAllRuleNodeIdsByTypeAndVersionLessThan(String type, int version, PageLink pageLink); + + List findAllRuleNodeByIds(List ruleNodeIds); + List findByExternalIds(RuleChainId ruleChainId, List externalIds); void deleteByIdIn(List ruleNodeIds); + } 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 827b73a0c1..de5ff109d3 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 @@ -79,6 +79,22 @@ public class JpaRuleNodeDao extends JpaAbstractDao imp DaoUtil.toPageable(pageLink))); } + @Override + public PageData findAllRuleNodeIdsByTypeAndVersionLessThan(String type, int version, PageLink pageLink) { + return DaoUtil.pageToPageData(ruleNodeRepository + .findAllRuleNodeIdsByTypeAndVersionLessThan( + type, + version, + DaoUtil.toPageable(pageLink))) + .mapData(RuleNodeId::new); + } + + @Override + public List findAllRuleNodeByIds(List ruleNodeIds) { + return DaoUtil.convertDataList(ruleNodeRepository.findAllById( + ruleNodeIds.stream().map(RuleNodeId::getId).collect(Collectors.toList()))); + } + @Override public List findByExternalIds(RuleChainId ruleChainId, List externalIds) { return DaoUtil.convertDataList(ruleNodeRepository.findRuleNodesByRuleChainIdAndExternalIdIn(ruleChainId.getId(), 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 c8ecb8000b..f02072b356 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 @@ -50,6 +50,11 @@ public interface RuleNodeRepository extends JpaRepository @Param("searchText") String searchText, Pageable pageable); + @Query("SELECT r.id FROM RuleNodeEntity r WHERE r.type = :ruleType AND r.configurationVersion < :version") + Page findAllRuleNodeIdsByTypeAndVersionLessThan(@Param("ruleType") String ruleType, + @Param("version") int version, + Pageable pageable); + List findRuleNodesByRuleChainIdAndExternalIdIn(UUID ruleChainId, List externalIds); @Transactional diff --git a/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java b/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java index 6e77927233..2f1c73da01 100644 --- a/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java +++ b/dao/src/test/java/org/thingsboard/server/dao/sql/rule/JpaRuleNodeDaoTest.java @@ -22,6 +22,7 @@ import org.junit.Before; import org.junit.Test; import org.springframework.beans.factory.annotation.Autowired; import org.thingsboard.common.util.JacksonUtil; +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; @@ -36,10 +37,10 @@ import org.thingsboard.server.dao.rule.RuleNodeDao; import java.util.ArrayList; import java.util.List; import java.util.UUID; +import java.util.stream.Collectors; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; public class JpaRuleNodeDaoTest extends AbstractJpaDaoTest { @@ -124,7 +125,39 @@ public class JpaRuleNodeDaoTest extends AbstractJpaDaoTest { assertEquals(10, ruleNodes.getData().size()); } + @Test + public void testFindRuleNodeIdsByTypeAndVersionLessThan() { + PageData ruleNodeIds = ruleNodeDao.findAllRuleNodeIdsByTypeAndVersionLessThan( "A", 1, new PageLink(10, 0, PREFIX_FOR_RULE_NODE_NAME)); + assertEquals(20, ruleNodeIds.getTotalElements()); + assertEquals(2, ruleNodeIds.getTotalPages()); + assertEquals(10, ruleNodeIds.getData().size()); + + ruleNodeIds = ruleNodeDao.findAllRuleNodeIdsByTypeAndVersionLessThan( "A", 1, new PageLink(10, 0)); + assertEquals(20, ruleNodeIds.getTotalElements()); + assertEquals(2, ruleNodeIds.getTotalPages()); + assertEquals(10, ruleNodeIds.getData().size()); + + // test - search text ignored + ruleNodeIds = ruleNodeDao.findAllRuleNodeIdsByTypeAndVersionLessThan( "A", 1, new PageLink(10, 0, StringUtils.randomAlphabetic(5))); + assertEquals(20, ruleNodeIds.getTotalElements()); + assertEquals(2, ruleNodeIds.getTotalPages()); + assertEquals(10, ruleNodeIds.getData().size()); + } + + @Test + public void testFindAllRuleNodeByIds() { + var fromUUIDs = ruleNodeIds.stream().map(RuleNodeId::new).collect(Collectors.toList()); + var ruleNodes = ruleNodeDao.findAllRuleNodeByIds(fromUUIDs); + assertEquals(40, ruleNodes.size()); + } + private List createRuleNodes(TenantId tenantId1, TenantId tenantId2, RuleChainId ruleChainId1, RuleChainId ruleChainId2, int count) { + return createRuleNodes(tenantId1, tenantId2, ruleChainId1, ruleChainId2, "A", "B", count); + } + + private List createRuleNodes(TenantId tenantId1, TenantId tenantId2, + RuleChainId ruleChainId1, RuleChainId ruleChainId2, + String typeA, String typeB, int count) { var chain1 = new RuleChain(ruleChainId1); chain1.setTenantId(tenantId1); chain1.setName(ruleChainId1.toString()); @@ -135,8 +168,8 @@ public class JpaRuleNodeDaoTest extends AbstractJpaDaoTest { ruleChainDao.save(tenantId2, chain2); List savedRuleNodeIds = new ArrayList<>(); for (int i = 0; i < count / 2; i++) { - savedRuleNodeIds.add(ruleNodeDao.save(tenantId1, getRuleNode(ruleChainId1, "A", Integer.toString(i))).getUuidId()); - savedRuleNodeIds.add(ruleNodeDao.save(tenantId2, getRuleNode(ruleChainId2, "B", Integer.toString(i + count / 2))).getUuidId()); + savedRuleNodeIds.add(ruleNodeDao.save(tenantId1, getRuleNode(ruleChainId1, typeA, Integer.toString(i))).getUuidId()); + savedRuleNodeIds.add(ruleNodeDao.save(tenantId2, getRuleNode(ruleChainId2, typeB, Integer.toString(i + count / 2))).getUuidId()); } return savedRuleNodeIds; } From 0abe2f24521e9587febf4dd6590c61b72458d685 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 18 Oct 2023 11:10:15 +0300 Subject: [PATCH 196/267] UI: Disabled line height --- .../lib/settings/common/font-settings-panel.component.ts | 6 +++++- .../widget/lib/settings/common/font-settings.component.ts | 7 ++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts index c99efa8931..562001e3c4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.ts @@ -69,6 +69,10 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit @coerceBoolean() autoScale = false; + @Input() + @coerceBoolean() + disabledLineHeight = false; + @Input() popover: TbPopoverComponent; @@ -106,7 +110,7 @@ export class FontSettingsPanelComponent extends PageComponent implements OnInit family: [this.font?.family, []], weight: [this.font?.weight, []], style: [this.font?.style, []], - lineHeight: [{ value: this.font?.lineHeight, disabled: this.autoScale }, []] + lineHeight: [{ value: this.font?.lineHeight, disabled: this.autoScale || this.disabledLineHeight }, []] } ); this.updatePreviewStyle(this.font); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts index 2c3780f1fe..0fc3b20da1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings.component.ts @@ -54,6 +54,10 @@ export class FontSettingsComponent implements OnInit, ControlValueAccessor { @coerceBoolean() autoScale = false; + @Input() + @coerceBoolean() + disabledLineHeight = false; + private modelValue: Font; private propagateChange = null; @@ -92,7 +96,8 @@ export class FontSettingsComponent implements OnInit, ControlValueAccessor { font: this.modelValue, initialPreviewStyle: this.initialPreviewStyle, clearButton: this.clearButton, - autoScale: this.autoScale + autoScale: this.autoScale, + disabledLineHeight: this.disabledLineHeight }; if (isDefinedAndNotNull(this.previewText)) { const previewText = typeof this.previewText === 'string' ? this.previewText : this.previewText(); From 954961f064ec509e9e8eb0df7bae2d77b7ffc236 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 18 Oct 2023 12:51:14 +0300 Subject: [PATCH 197/267] UI: Hide line height --- .../lib/settings/common/font-settings-panel.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html index ac103fe395..44163fae26 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/font-settings-panel.component.html @@ -73,7 +73,7 @@
-
+
widgets.widget-font.line-height
From ef292c5cbb026328cfe7ed503f6a9805503cb216 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 18 Oct 2023 12:56:01 +0300 Subject: [PATCH 198/267] Fix delete queries in repositories --- .../server/dao/sql/alarm/EntityAlarmRepository.java | 4 +++- .../dao/sql/notification/NotificationRepository.java | 12 +++++++++--- .../notification/NotificationRequestRepository.java | 8 ++++++-- .../sql/notification/NotificationRuleRepository.java | 5 ++++- .../notification/NotificationTargetRepository.java | 5 ++++- .../notification/NotificationTemplateRepository.java | 5 ++++- 6 files changed, 30 insertions(+), 9 deletions(-) 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 f6250e98f0..2ed2364621 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 @@ -36,6 +36,8 @@ public interface EntityAlarmRepository extends JpaRepository findByRequestId(UUID requestId, Pageable pageable); @Transactional - int deleteByIdAndRecipientId(UUID id, UUID recipientId); + @Modifying + @Query("DELETE FROM NotificationEntity n WHERE n.id = :id AND n.recipientId = :recipientId") + int deleteByIdAndRecipientId(@Param("id") UUID id, @Param("recipientId") UUID recipientId); @Transactional - void deleteByRequestId(UUID requestId); + @Modifying + @Query("DELETE FROM NotificationEntity n WHERE n.requestId = :requestId") + void deleteByRequestId(@Param("requestId") UUID requestId); @Transactional - void deleteByRecipientId(UUID recipientId); + @Modifying + @Query("DELETE FROM NotificationEntity n WHERE n.recipientId = :recipientId") + void deleteByRecipientId(@Param("recipientId") UUID recipientId); @Modifying @Transactional diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java index 126295616f..e7f3ac529b 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationRequestRepository.java @@ -70,9 +70,13 @@ public interface NotificationRequestRepository extends JpaRepository findByTenantIdAndIdIn(UUID tenantId, List ids); @Transactional - void deleteByTenantId(UUID tenantId); + @Modifying + @Query("DELETE FROM NotificationTargetEntity t WHERE t.tenantId = :tenantId") + void deleteByTenantId(@Param("tenantId") UUID tenantId); long countByTenantId(UUID tenantId); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java index 73a25b98c3..3e68819b26 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/notification/NotificationTemplateRepository.java @@ -18,6 +18,7 @@ package org.thingsboard.server.dao.sql.notification; 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.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; import org.springframework.stereotype.Repository; @@ -42,7 +43,9 @@ public interface NotificationTemplateRepository extends JpaRepository Date: Wed, 18 Oct 2023 12:59:28 +0300 Subject: [PATCH 199/267] UI: fixed message 'No data to display on widget' not showing when there is no data for timeseries and value chart widgets --- .../lib/cards/aggregated-value-card-widget.component.ts | 4 ++-- .../home/components/widget/lib/flot-widget.component.ts | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts index 5380874811..e81cb270e7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts @@ -116,7 +116,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit ngOnInit(): void { this.ctx.$scope.aggregatedValueCardWidget = this; this.settings = {...aggregatedValueCardDefaultSettings, ...this.ctx.settings}; - this.showSubtitle = this.settings.showSubtitle; + this.showSubtitle = this.settings.showSubtitle && this.ctx.datasources?.length > 0; const subtitle = this.settings.subtitle; this.subtitle$ = this.ctx.registerLabelPattern(subtitle, this.subtitle$); this.subtitleStyle = textStyle(this.settings.subtitleFont, '0.25px'); @@ -156,7 +156,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit } ngAfterViewInit(): void { - if (this.showChart) { + if (this.showChart && this.ctx.datasources?.length) { const settings = { shadowSize: 0, enableSelection: false, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.component.ts index 9272295a27..1494e987ce 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.component.ts @@ -60,7 +60,9 @@ export class FlotWidgetComponent implements OnInit { this.settings = this.ctx.settings; this.chartType = this.chartType || 'line'; this.configureLegend(); - this.flot = new TbFlot(this.ctx, this.chartType, $(this.flotElement.nativeElement)); + if (this.ctx.datasources?.length) { + this.flot = new TbFlot(this.ctx, this.chartType, $(this.flotElement.nativeElement)); + } } private configureLegend(): void { From 114419775391c974f8ab09b75c75c6c216ec154b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 18 Oct 2023 15:14:16 +0300 Subject: [PATCH 200/267] UI: Add default data keys/latest data keys functions to widget type parameters. --- .../system/widget_types/battery_level.json | 2 +- .../system/widget_types/entities_table.json | 5 +- .../system/widget_types/progress_bar.json | 2 +- .../system/widget_types/signal_strength.json | 2 +- .../json/system/widget_types/simple_card.json | 5 +- .../simple_value_and_chart_card.json | 2 +- .../json/system/widget_types/state_chart.json | 5 +- .../widget_types/timeseries_bar_chart.json | 5 +- .../widget_types/timeseries_line_chart.json | 5 +- .../system/widget_types/timeseries_table.json | 5 +- .../widget_types/value_and_chart_card.json | 5 +- .../json/system/widget_types/value_card.json | 5 +- .../wind_speed_and_direction.json | 2 +- ...gated-value-card-basic-config.component.ts | 99 +++++++++++++++++-- .../progress-bar-basic-config.component.ts | 5 +- .../simple-card-basic-config.component.ts | 5 +- ...timeseries-table-basic-config.component.ts | 5 +- .../value-card-basic-config.component.ts | 5 +- ...value-chart-card-basic-config.component.ts | 14 +-- .../chart/flot-basic-config.component.ts | 5 +- .../entities-table-basic-config.component.ts | 4 +- .../battery-level-basic-config.component.ts | 5 +- .../signal-strength-basic-config.component.ts | 5 +- ...-speed-direction-basic-config.component.ts | 8 +- .../config/widget-config.component.models.ts | 29 +++++- .../lib/cards/aggregated-value-card.models.ts | 69 ------------- .../widget/widget-component.service.ts | 6 ++ ui-ngx/src/app/shared/models/widget.models.ts | 2 + 28 files changed, 188 insertions(+), 128 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/battery_level.json b/application/src/main/data/json/system/widget_types/battery_level.json index 695a0dc525..1a9bdd1afd 100644 --- a/application/src/main/data/json/system/widget_types/battery_level.json +++ b/application/src/main/data/json/system/widget_types/battery_level.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.batteryLevelWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.batteryLevelWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '200px',\n previewHeight: '200px',\n embedTitlePanel: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.batteryLevelWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.batteryLevelWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '200px',\n previewHeight: '200px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'batteryLevel', label: 'batteryLevel', type: 'timeseries' }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-battery-level-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/entities_table.json b/application/src/main/data/json/system/widget_types/entities_table.json index f7dbf57972..ec137f81cb 100644 --- a/application/src/main/data/json/system/widget_types/entities_table.json +++ b/application/src/main/data/json/system/widget_types/entities_table.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.entitiesTableWidget.onDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n hasDataPageLink: true,\n warnOnPageDataOverflow: false,\n dataKeysOptional: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'name', type: 'entityField' }];\n }\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n },\n 'rowDoubleClick': {\n name: 'widget-action.row-double-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-entities-table-widget-settings", @@ -20,5 +20,6 @@ "basicModeDirective": "tb-entities-table-basic-config", "defaultConfig": "{\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":86400000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"4px\",\"settings\":{\"enableSearch\":true,\"enableSelectColumnDisplay\":true,\"enableStickyHeader\":true,\"enableStickyAction\":true,\"reserveSpaceForHiddenAction\":\"true\",\"displayEntityName\":false,\"displayEntityLabel\":false,\"displayEntityType\":false,\"displayPagination\":true,\"defaultPageSize\":10,\"defaultSortOrder\":\"name\",\"useRowStyleFunction\":false,\"entitiesTitle\":\"Entities\"},\"title\":\"Entities table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"datasources\":[{\"type\":\"function\",\"name\":\"Simulated\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Entity name\",\"color\":\"#2196f3\",\"settings\":{\"columnWidth\":\"0px\",\"useCellStyleFunction\":false,\"cellStyleFunction\":\"\",\"useCellContentFunction\":false,\"cellContentFunction\":\"\"},\"_hash\":0.472295003170325,\"funcBody\":\"return 'Simulated';\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Entity type\",\"color\":\"#607d8b\",\"settings\":{},\"_hash\":0.782057645776538,\"funcBody\":\"return 'Device';\",\"decimals\":null,\"aggregationType\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Sin\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.904797781901171,\"funcBody\":\"return Math.round(1000*Math.sin(time/5000));\",\"decimals\":0},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Cos\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.1961430898042078,\"funcBody\":\"return Math.round(1000*Math.cos(time/5000));\",\"decimals\":0},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Random\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.7678057538205878,\"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;\",\"decimals\":2}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"displayTimewindow\":false,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"list\",\"iconColor\":null}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/progress_bar.json b/application/src/main/data/json/system/widget_types/progress_bar.json index df3dcf6268..cd22b4b73e 100644 --- a/application/src/main/data/json/system/widget_types/progress_bar.json +++ b/application/src/main/data/json/system/widget_types/progress_bar.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'humidity', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-progress-bar-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/signal_strength.json b/application/src/main/data/json/system/widget_types/signal_strength.json index 90c051c803..a24a00edd5 100644 --- a/application/src/main/data/json/system/widget_types/signal_strength.json +++ b/application/src/main/data/json/system/widget_types/signal_strength.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.signalStrengthWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.signalStrengthWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '200px',\n previewHeight: '200px',\n embedTitlePanel: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.signalStrengthWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.signalStrengthWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '200px',\n previewHeight: '200px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rssi', label: 'rssi', type: 'timeseries' }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-signal-strength-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/simple_card.json b/application/src/main/data/json/system/widget_types/simple_card.json index 063454ee6f..b43f4a12af 100644 --- a/application/src/main/data/json/system/widget_types/simple_card.json +++ b/application/src/main/data/json/system/widget_types/simple_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "", "templateCss": "#container {\n overflow: auto;\n}\n\n.tbDatasource-container {\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n\n.tbDatasource-table {\n width: 100%;\n height: 100%;\n border-collapse: collapse;\n white-space: nowrap;\n font-weight: 100;\n text-align: right;\n}\n\n.tbDatasource-table td {\n padding: 12px;\n position: relative;\n box-sizing: border-box;\n}\n\n.tbDatasource-data-key {\n opacity: 0.7;\n font-weight: 400;\n font-size: 3.500rem;\n}\n\n.tbDatasource-value {\n font-size: 5.000rem;\n}", - "controllerScript": "self.onInit = function() {\n\n self.ctx.labelPosition = self.ctx.settings.labelPosition || 'left';\n \n if (self.ctx.datasources.length > 0) {\n var tbDatasource = self.ctx.datasources[0];\n var datasourceId = 'tbDatasource' + 0;\n self.ctx.$container.append(\n \"
\"\n );\n \n self.ctx.datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n \n var tableId = 'table' + 0;\n self.ctx.datasourceContainer.append(\n \"
\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n if (self.ctx.labelPosition === 'top') {\n table.css('text-align', 'left');\n }\n \n if (tbDatasource.dataKeys.length > 0) {\n var dataKey = tbDatasource.dataKeys[0];\n var labelCellId = 'labelCell' + 0;\n var cellId = 'cell' + 0;\n if (self.ctx.labelPosition === 'left') {\n table.append(\n \"\" +\n dataKey.label +\n \"\");\n } else {\n table.append(\n \"\" +\n dataKey.label +\n \"\");\n }\n self.ctx.labelCell = $('#' + labelCellId, table);\n self.ctx.valueCell = $('#' + cellId, table);\n self.ctx.valueCell.html(0 + ' ' + self.ctx.units);\n }\n }\n \n $.fn.textWidth = function(){\n var html_org = $(this).html();\n var html_calc = '' + html_org + '';\n $(this).html(html_calc);\n var width = $(this).find('span:first').width();\n $(this).html(html_org);\n return width;\n }; \n \n self.onResize();\n};\n\nself.onDataUpdated = function() {\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n if (self.ctx.valueCell && self.ctx.data.length > 0) {\n var cellData = self.ctx.data[0];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var txtValue;\n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (self.ctx.datasources.length > 0 && self.ctx.datasources[0].dataKeys.length > 0) {\n dataKey = self.ctx.datasources[0].dataKeys[0];\n if (dataKey.decimals || dataKey.decimals === 0) {\n decimals = dataKey.decimals;\n }\n if (dataKey.units) {\n units = dataKey.units;\n }\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, true);\n } else {\n txtValue = value;\n }\n self.ctx.valueCell.html(txtValue);\n var targetWidth;\n var minDelta;\n if (self.ctx.labelPosition === 'left') {\n targetWidth = self.ctx.datasourceContainer.width() - self.ctx.labelCell.width();\n minDelta = self.ctx.width/16 + self.ctx.padding;\n } else {\n targetWidth = self.ctx.datasourceContainer.width();\n minDelta = self.ctx.padding;\n }\n var delta = targetWidth - self.ctx.valueCell.textWidth();\n var fontSize = self.ctx.valueFontSize;\n if (targetWidth > minDelta) {\n while (delta < minDelta && fontSize > 6) {\n fontSize--;\n self.ctx.valueCell.css('font-size', fontSize+'px');\n delta = targetWidth - self.ctx.valueCell.textWidth();\n }\n }\n }\n } \n \n};\n\nself.onResize = function() {\n var labelFontSize;\n if (self.ctx.labelPosition === 'top') {\n self.ctx.padding = self.ctx.height/20;\n labelFontSize = self.ctx.height/4;\n self.ctx.valueFontSize = self.ctx.height/2;\n } else {\n self.ctx.padding = self.ctx.width/50;\n labelFontSize = self.ctx.height/2.5;\n self.ctx.valueFontSize = self.ctx.height/2;\n if (self.ctx.width/self.ctx.height <= 2.7) {\n labelFontSize = self.ctx.width/7;\n self.ctx.valueFontSize = self.ctx.width/6;\n }\n }\n self.ctx.padding = Math.min(12, self.ctx.padding);\n \n if (self.ctx.labelCell) {\n self.ctx.labelCell.css('font-size', labelFontSize+'px');\n self.ctx.labelCell.css('padding', self.ctx.padding+'px');\n }\n if (self.ctx.valueCell) {\n self.ctx.valueCell.css('font-size', self.ctx.valueFontSize+'px');\n self.ctx.valueCell.css('padding', self.ctx.padding+'px');\n } \n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n\n self.ctx.labelPosition = self.ctx.settings.labelPosition || 'left';\n \n if (self.ctx.datasources.length > 0) {\n var tbDatasource = self.ctx.datasources[0];\n var datasourceId = 'tbDatasource' + 0;\n self.ctx.$container.append(\n \"
\"\n );\n \n self.ctx.datasourceContainer = $('#' + datasourceId,\n self.ctx.$container);\n \n var tableId = 'table' + 0;\n self.ctx.datasourceContainer.append(\n \"
\"\n );\n var table = $('#' + tableId, self.ctx.$container);\n if (self.ctx.labelPosition === 'top') {\n table.css('text-align', 'left');\n }\n \n if (tbDatasource.dataKeys.length > 0) {\n var dataKey = tbDatasource.dataKeys[0];\n var labelCellId = 'labelCell' + 0;\n var cellId = 'cell' + 0;\n if (self.ctx.labelPosition === 'left') {\n table.append(\n \"\" +\n dataKey.label +\n \"\");\n } else {\n table.append(\n \"\" +\n dataKey.label +\n \"\");\n }\n self.ctx.labelCell = $('#' + labelCellId, table);\n self.ctx.valueCell = $('#' + cellId, table);\n self.ctx.valueCell.html(0 + ' ' + self.ctx.units);\n }\n }\n \n $.fn.textWidth = function(){\n var html_org = $(this).html();\n var html_calc = '' + html_org + '';\n $(this).html(html_calc);\n var width = $(this).find('span:first').width();\n $(this).html(html_org);\n return width;\n }; \n \n self.onResize();\n};\n\nself.onDataUpdated = function() {\n \n function isNumber(n) {\n return !isNaN(parseFloat(n)) && isFinite(n);\n }\n\n if (self.ctx.valueCell && self.ctx.data.length > 0) {\n var cellData = self.ctx.data[0];\n if (cellData.data.length > 0) {\n var tvPair = cellData.data[cellData.data.length -\n 1];\n var value = tvPair[1];\n var txtValue;\n if (isNumber(value)) {\n var decimals = self.ctx.decimals;\n var units = self.ctx.units;\n if (self.ctx.datasources.length > 0 && self.ctx.datasources[0].dataKeys.length > 0) {\n dataKey = self.ctx.datasources[0].dataKeys[0];\n if (dataKey.decimals || dataKey.decimals === 0) {\n decimals = dataKey.decimals;\n }\n if (dataKey.units) {\n units = dataKey.units;\n }\n }\n txtValue = self.ctx.utils.formatValue(value, decimals, units, true);\n } else {\n txtValue = value;\n }\n self.ctx.valueCell.html(txtValue);\n var targetWidth;\n var minDelta;\n if (self.ctx.labelPosition === 'left') {\n targetWidth = self.ctx.datasourceContainer.width() - self.ctx.labelCell.width();\n minDelta = self.ctx.width/16 + self.ctx.padding;\n } else {\n targetWidth = self.ctx.datasourceContainer.width();\n minDelta = self.ctx.padding;\n }\n var delta = targetWidth - self.ctx.valueCell.textWidth();\n var fontSize = self.ctx.valueFontSize;\n if (targetWidth > minDelta) {\n while (delta < minDelta && fontSize > 6) {\n fontSize--;\n self.ctx.valueCell.css('font-size', fontSize+'px');\n delta = targetWidth - self.ctx.valueCell.textWidth();\n }\n }\n }\n } \n \n};\n\nself.onResize = function() {\n var labelFontSize;\n if (self.ctx.labelPosition === 'top') {\n self.ctx.padding = self.ctx.height/20;\n labelFontSize = self.ctx.height/4;\n self.ctx.valueFontSize = self.ctx.height/2;\n } else {\n self.ctx.padding = self.ctx.width/50;\n labelFontSize = self.ctx.height/2.5;\n self.ctx.valueFontSize = self.ctx.height/2;\n if (self.ctx.width/self.ctx.height <= 2.7) {\n labelFontSize = self.ctx.width/7;\n self.ctx.valueFontSize = self.ctx.width/6;\n }\n }\n self.ctx.padding = Math.min(12, self.ctx.padding);\n \n if (self.ctx.labelCell) {\n self.ctx.labelCell.css('font-size', labelFontSize+'px');\n self.ctx.labelCell.css('padding', self.ctx.padding+'px');\n }\n if (self.ctx.valueCell) {\n self.ctx.valueCell.css('font-size', self.ctx.valueFontSize+'px');\n self.ctx.valueCell.css('padding', self.ctx.padding+'px');\n } \n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-simple-card-widget-settings", @@ -19,5 +19,6 @@ "basicModeDirective": "tb-simple-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"#ff5722\",\"color\":\"rgba(255, 255, 255, 0.87)\",\"padding\":\"16px\",\"settings\":{\"labelPosition\":\"top\"},\"title\":\"Simple card\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json b/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json index 7fa97f4a52..e19ff918be 100644 --- a/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json +++ b/application/src/main/data/json/system/widget_types/simple_value_and_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(63, 82, 221, 1)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'temperature', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/state_chart.json b/application/src/main/data/json/system/widget_types/state_chart.json index 2b04282d17..25a3130d48 100644 --- a/application/src/main/data/json/system/widget_types/state_chart.json +++ b/application/src/main/data/json/system/widget_types/state_chart.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n stateData: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries', units: '°C', decimals: 0 }];\n }\n };\n}\n\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-flot-line-widget-settings", @@ -21,5 +21,6 @@ "basicModeDirective": "tb-flot-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"waterfall_chart\",\"iconColor\":\"#1F6BDD\"}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/timeseries_bar_chart.json b/application/src/main/data/json/system/widget_types/timeseries_bar_chart.json index baf662a9de..ff9c7971f0 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_bar_chart.json +++ b/application/src/main/data/json/system/widget_types/timeseries_bar_chart.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries', units: '°C', decimals: 0 }];\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "settingsDirective": "tb-flot-bar-widget-settings", @@ -21,5 +21,6 @@ "basicModeDirective": "tb-flot-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":false,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 100 - 50;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 1000) {\\n\\tvalue = 1000;\\n}\\nreturn value;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000},\"aggregation\":{\"limit\":200,\"type\":\"AVG\"}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":true,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"defaultBarWidth\":600,\"barAlignment\":\"left\",\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Bar Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/timeseries_line_chart.json b/application/src/main/data/json/system/widget_types/timeseries_line_chart.json index 27d2b8881e..e83b213ae0 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_line_chart.json +++ b/application/src/main/data/json/system/widget_types/timeseries_line_chart.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.flotWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.flotWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.flotWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.flotWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.flotWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries', units: '°C', decimals: 0 }];\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", @@ -22,5 +22,6 @@ "basicModeDirective": "tb-flot-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"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;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false},\"_hash\":0.12775350966079668,\"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\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false},\"title\":\"Timeseries Line Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":false,\"titleIcon\":\"thermostat\",\"iconColor\":\"#1F6BDD\"}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/timeseries_table.json b/application/src/main/data/json/system/widget_types/timeseries_table.json index b16672a942..d267d42763 100644 --- a/application/src/main/data/json/system/widget_types/timeseries_table.json +++ b/application/src/main/data/json/system/widget_types/timeseries_table.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", + "controllerScript": "self.onInit = function() {\n}\n\nself.onDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onDataUpdated();\n}\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.timeseriesTableWidget.onLatestDataUpdated();\n}\n\nself.typeParameters = function() {\n return {\n ignoreDataUpdateOnIntervalTick: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries', units: '°C', decimals: 0 }];\n }\n };\n}\n\nself.actionSources = function() {\n return {\n 'actionCellButton': {\n name: 'widget-action.action-cell-button',\n multiple: true,\n hasShowCondition: true\n },\n 'rowClick': {\n name: 'widget-action.row-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n}\n", "settingsSchema": "", "dataKeySettingsSchema": "", "latestDataKeySettingsSchema": "", @@ -22,5 +22,6 @@ "basicModeDirective": "tb-timeseries-table-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"entityAliasId\":null,\"filterId\":null,\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature °C\",\"color\":\"#2196f3\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = (value + 60)/120 * 100;\\n var color = tinycolor.mix('blue', 'red', percent);\\n color.setAlpha(.5);\\n return {\\n paddingLeft: '20px',\\n color: '#ffffff',\\n background: color.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity, %\",\"color\":\"#ffc107\",\"settings\":{\"useCellStyleFunction\":true,\"cellStyleFunction\":\"if (value) {\\n var percent = value;\\n var backgroundColor = tinycolor('blue');\\n backgroundColor.setAlpha(value/100);\\n var color = 'blue';\\n if (value > 50) {\\n color = 'white';\\n }\\n \\n return {\\n paddingLeft: '20px',\\n color: color,\\n background: backgroundColor.toRgbString(),\\n fontSize: '18px'\\n };\\n} else {\\n return {};\\n}\",\"useCellContentFunction\":false},\"_hash\":0.12775350966079668,\"funcBody\":\"var value = prevValue + Math.random() * 20 - 10;\\nvar multiplier = Math.pow(10, 1 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value;\"}],\"latestDataKeys\":null}],\"timewindow\":{\"realtime\":{\"interval\":1000,\"timewindowMs\":60000},\"aggregation\":{\"type\":\"NONE\",\"limit\":200}},\"showTitle\":true,\"backgroundColor\":\"rgb(255, 255, 255)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"showTimestamp\":true,\"displayPagination\":true,\"defaultPageSize\":10},\"title\":\"Timeseries table\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400,\"padding\":\"5px 10px 5px 10px\"},\"useDashboardTimewindow\":false,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"showTitleIcon\":false,\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"displayTimewindow\":true,\"configMode\":\"basic\"}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/value_and_chart_card.json b/application/src/main/data/json/system/widget_types/value_and_chart_card.json index 3efb2c3b44..aa8e6b31ee 100644 --- a/application/src/main/data/json/system/widget_types/value_and_chart_card.json +++ b/application/src/main/data/json/system/widget_types/value_and_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'watermeter', label: 'Watermeter', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³');\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", @@ -22,5 +22,6 @@ "basicModeDirective": "tb-aggregated-value-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"watermeter\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 80) {\\n\\tvalue = 80;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m³\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 10 - 5;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < 5) {\\n\\tvalue = 5;\\n} else if (value > 80) {\\n\\tvalue = 80;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m³\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"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;\",\"aggregationType\":null,\"units\":\"m³\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Value and chart card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"water_drop\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/value_card.json b/application/src/main/data/json/system/widget_types/value_card.json index c2fb6dd274..eb676a517f 100644 --- a/application/src/main/data/json/system/widget_types/value_card.json +++ b/application/src/main/data/json/system/widget_types/value_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", @@ -19,5 +19,6 @@ "basicModeDirective": "tb-value-card-basic-config", "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json index 1c4f7ecb7c..dff8b3cacc 100644 --- a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'winddirection', label: 'windDirection', type: 'timeseries' },\n { name: 'windspeed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-wind-speed-direction-widget-settings", diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts index 90a020cac8..ad88ee79a0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts @@ -20,7 +20,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; -import { DataKey, Datasource, WidgetConfig, } from '@shared/models/widget.models'; +import { ComparisonResultType, DataKey, Datasource, WidgetConfig, } from '@shared/models/widget.models'; import { WidgetConfigComponent } from '@home/components/widget/widget-config.component'; import { DataKeyType } from '@shared/models/telemetry/telemetry.models'; import { @@ -29,15 +29,19 @@ import { } from '@home/components/widget/config/timewindow-config-panel.component'; import { isUndefined } from '@core/utils'; import { + ColorType, + constantColor, cssSizeToStrSize, DateFormatProcessor, - DateFormatSettings, getDataKey, + DateFormatSettings, + getDataKey, resolveCssSize } from '@shared/models/widget-settings.models'; import { aggregatedValueCardDefaultSettings, - AggregatedValueCardWidgetSettings, - createDefaultAggregatedValueLatestDataKeys + AggregatedValueCardKeyPosition, + AggregatedValueCardKeySettings, + AggregatedValueCardWidgetSettings } from '@home/components/widget/lib/cards/aggregated-value-card.models'; import { AggregationType, @@ -89,11 +93,7 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo } protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [ - { name: 'watermeter', label: 'Watermeter', type: DataKeyType.timeseries, color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 } - ], - createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³') - ); + super.setupDefaults(configData); configData.config.useDashboardTimewindow = false; configData.config.displayTimewindow = true; configData.config.timewindow = { @@ -110,6 +110,87 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo }; } + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [ + { name: 'watermeter', label: 'Watermeter', type: DataKeyType.timeseries, color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 } + ]; + } + + protected defaultLatestDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return this.createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³'); + } + + createDefaultAggregatedValueLatestDataKeys(keyName: string, units): DataKey[] { + return [ + { + name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals: 0, + aggregationType: AggregationType.NONE, + settings: { + position: AggregatedValueCardKeyPosition.center, + font: { + family: 'Roboto', + size: 52, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.87)'), + showArrow: false + } as AggregatedValueCardKeySettings + }, + { + name: keyName, label: 'Delta percent', type: DataKeyType.timeseries, units: '%', decimals: 0, + aggregationType: AggregationType.AVG, + comparisonEnabled: true, + timeForComparison: 'previousInterval', + comparisonResultType: ComparisonResultType.DELTA_PERCENT, + settings: { + position: AggregatedValueCardKeyPosition.rightTop, + font: { + family: 'Roboto', + size: 14, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: { + color: 'rgba(0, 0, 0, 0.87)', + type: ColorType.range, + rangeList: [ + {to: 0, color: '#198038'}, + {from: 0, to: 0, color: 'rgba(0, 0, 0, 0.87)'}, + {from: 0, color: '#D12730'} + ], + colorFunction: '' + }, + showArrow: true + } as AggregatedValueCardKeySettings + }, + { + name: keyName, label: 'Delta absolute', type: DataKeyType.timeseries, units, decimals: 1, + aggregationType: AggregationType.AVG, + comparisonEnabled: true, + timeForComparison: 'previousInterval', + comparisonResultType: ComparisonResultType.DELTA_ABSOLUTE, + settings: { + position: AggregatedValueCardKeyPosition.rightBottom, + font: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.38)'), + showArrow: false + } as AggregatedValueCardKeySettings + } + ]; + } + protected onConfigSet(configData: WidgetConfigComponentData) { const settings: AggregatedValueCardWidgetSettings = {...aggregatedValueCardDefaultSettings, ...(configData.config.settings || {})}; const dataKey = getDataKey(configData.config.datasources); diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts index ef54d64861..7a2a1d7291 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/progress-bar-basic-config.component.ts @@ -21,6 +21,7 @@ import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { + DataKey, datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, WidgetConfig, @@ -80,8 +81,8 @@ export class ProgressBarBasicConfigComponent extends BasicWidgetConfigComponent return this.progressBarWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'humidity', label: 'humidity', type: DataKeyType.timeseries }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'humidity', label: 'humidity', type: DataKeyType.timeseries }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts index 9b2a6a764b..55f56466af 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/simple-card-basic-config.component.ts @@ -21,6 +21,7 @@ import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { + DataKey, datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, WidgetConfig, @@ -63,8 +64,8 @@ export class SimpleCardBasicConfigComponent extends BasicWidgetConfigComponent { return this.simpleCardWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts index dc2a41b816..b99c005da0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/timeseries-table-basic-config.component.ts @@ -57,9 +57,8 @@ export class TimeseriesTableBasicConfigComponent extends BasicWidgetConfigCompon return this.timeseriesTableWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, - [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts index 629fce4081..19eeb2e301 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-card-basic-config.component.ts @@ -21,6 +21,7 @@ import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { + DataKey, datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, WidgetConfig, @@ -106,8 +107,8 @@ export class ValueCardBasicConfigComponent extends BasicWidgetConfigComponent { super.setupConfig(widgetConfig); } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts index f2c3a853a0..8980a3ced4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/value-chart-card-basic-config.component.ts @@ -72,12 +72,14 @@ export class ValueChartCardBasicConfigComponent extends BasicWidgetConfigCompone return this.valueChartCardWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [ - { name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, color: 'rgba(63, 82, 221, 1)'} - ], - [{ name: 'temperature', label: 'Latest', type: DataKeyType.timeseries}] - ); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [ + { name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, color: 'rgba(63, 82, 221, 1)'} + ]; + } + + protected defaultLatestDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'temperature', label: 'Latest', type: DataKeyType.timeseries}]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts index 050d362868..2b2618e25f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/chart/flot-basic-config.component.ts @@ -57,9 +57,8 @@ export class FlotBasicConfigComponent extends BasicWidgetConfigComponent { return this.flotWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, - [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'temperature', label: 'Temperature', type: DataKeyType.timeseries, units: '°C', decimals: 0 }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts index 228879e2ef..416c5ba404 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/entity/entities-table-basic-config.component.ts @@ -72,8 +72,8 @@ export class EntitiesTableBasicConfigComponent extends BasicWidgetConfigComponen return this.entitiesTableWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'name', type: DataKeyType.entityField }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'name', type: DataKeyType.entityField }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts index bb6af9d5ad..5ad6ca4fb4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/battery-level-basic-config.component.ts @@ -21,6 +21,7 @@ import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { + DataKey, datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, WidgetConfig, @@ -83,8 +84,8 @@ export class BatteryLevelBasicConfigComponent extends BasicWidgetConfigComponent return this.batteryLevelWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'batteryLevel', label: 'batteryLevel', type: DataKeyType.timeseries }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'batteryLevel', label: 'batteryLevel', type: DataKeyType.timeseries }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts index 9dd0325b75..86fe727447 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/indicator/signal-strength-basic-config.component.ts @@ -21,6 +21,7 @@ import { AppState } from '@core/core.state'; import { BasicWidgetConfigComponent } from '@home/components/widget/config/widget-config.component.models'; import { WidgetConfigComponentData } from '@home/models/widget-component.models'; import { + DataKey, datasourcesHasAggregation, datasourcesHasOnlyComparisonAggregation, WidgetConfig, @@ -85,8 +86,8 @@ export class SignalStrengthBasicConfigComponent extends BasicWidgetConfigCompone return this.signalStrengthWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'rssi', label: 'rssi', type: DataKeyType.timeseries }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'rssi', label: 'rssi', type: DataKeyType.timeseries }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts index 8435170ed3..45344aba84 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts @@ -107,10 +107,10 @@ export class WindSpeedDirectionBasicConfigComponent extends BasicWidgetConfigCom return this.windSpeedDirectionWidgetConfigForm; } - protected setupDefaults(configData: WidgetConfigComponentData) { - this.setupDefaultDatasource(configData, [{ name: 'winddirection', label: windDirectionLabel, type: DataKeyType.timeseries }, - { name: 'windspeed', label: centerValueLabel, type: DataKeyType.timeseries, - units: 'm/s', decimals: 1 }]); + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return [{ name: 'winddirection', label: windDirectionLabel, type: DataKeyType.timeseries }, + { name: 'windspeed', label: centerValueLabel, type: DataKeyType.timeseries, + units: 'm/s', decimals: 1 }]; } protected onConfigSet(configData: WidgetConfigComponentData) { diff --git a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts index 75112d7cfa..cfa0cedbee 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/widget-config.component.models.ts @@ -97,7 +97,34 @@ export abstract class BasicWidgetConfigComponent extends PageComponent implement }); } - protected setupDefaults(configData: WidgetConfigComponentData) {} + protected setupDefaults(configData: WidgetConfigComponentData) { + const params = configData.typeParameters; + let dataKeys: DataKey[]; + let latestDataKeys: DataKey[]; + if (params.defaultDataKeysFunction) { + dataKeys = params.defaultDataKeysFunction(this, configData); + } + if (params.defaultLatestDataKeysFunction) { + latestDataKeys = params.defaultLatestDataKeysFunction(this, configData); + } + if (!dataKeys) { + dataKeys = this.defaultDataKeys(configData); + } + if (!latestDataKeys) { + latestDataKeys = this.defaultLatestDataKeys(configData); + } + if (dataKeys || latestDataKeys) { + this.setupDefaultDatasource(configData, dataKeys, latestDataKeys); + } + } + + protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return null; + } + + protected defaultLatestDataKeys(configData: WidgetConfigComponentData): DataKey[] { + return null; + } protected updateValidators(emitEvent: boolean, trigger?: string) { } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts index c27fe9df96..b199aaa9c6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts @@ -161,72 +161,3 @@ export const aggregatedValueCardDefaultKeySettings: AggregatedValueCardKeySettin color: constantColor('rgba(0, 0, 0, 0.87)'), showArrow: false }; - -export const createDefaultAggregatedValueLatestDataKeys = (keyName: string, units): DataKey[] => [ - { - name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals: 0, - aggregationType: AggregationType.NONE, - settings: { - position: AggregatedValueCardKeyPosition.center, - font: { - family: 'Roboto', - size: 52, - sizeUnit: 'px', - style: 'normal', - weight: '500', - lineHeight: '1' - }, - color: constantColor('rgba(0, 0, 0, 0.87)'), - showArrow: false - } as AggregatedValueCardKeySettings - }, - { - name: keyName, label: 'Delta percent', type: DataKeyType.timeseries, units: '%', decimals: 0, - aggregationType: AggregationType.AVG, - comparisonEnabled: true, - timeForComparison: 'previousInterval', - comparisonResultType: ComparisonResultType.DELTA_PERCENT, - settings: { - position: AggregatedValueCardKeyPosition.rightTop, - font: { - family: 'Roboto', - size: 14, - sizeUnit: 'px', - style: 'normal', - weight: '500', - lineHeight: '1' - }, - color: { - color: 'rgba(0, 0, 0, 0.87)', - type: ColorType.range, - rangeList: [ - {to: 0, color: '#198038'}, - {from: 0, to: 0, color: 'rgba(0, 0, 0, 0.87)'}, - {from: 0, color: '#D12730'} - ], - colorFunction: '' - }, - showArrow: true - } as AggregatedValueCardKeySettings - }, - { - name: keyName, label: 'Delta absolute', type: DataKeyType.timeseries, units, decimals: 1, - aggregationType: AggregationType.AVG, - comparisonEnabled: true, - timeForComparison: 'previousInterval', - comparisonResultType: ComparisonResultType.DELTA_ABSOLUTE, - settings: { - position: AggregatedValueCardKeyPosition.rightBottom, - font: { - family: 'Roboto', - size: 11, - sizeUnit: 'px', - style: 'normal', - weight: '400', - lineHeight: '1' - }, - color: constantColor('rgba(0, 0, 0, 0.38)'), - showArrow: false - } as AggregatedValueCardKeySettings - } - ]; 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 f8023008f1..313993167d 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 @@ -552,6 +552,12 @@ export class WidgetComponentService { if (isUndefined(result.typeParameters.hideDataSettings)) { result.typeParameters.hideDataSettings = false; } + if (!isFunction(result.typeParameters.defaultDataKeysFunction)) { + result.typeParameters.defaultDataKeysFunction = null; + } + if (!isFunction(result.typeParameters.defaultLatestDataKeysFunction)) { + result.typeParameters.defaultLatestDataKeysFunction = null; + } if (isFunction(widgetTypeInstance.actionSources)) { result.actionSources = widgetTypeInstance.actionSources(); } else { diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index d10bbc433d..fd99eb37ee 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -180,6 +180,8 @@ export interface WidgetTypeParameters { previewHeight?: string; embedTitlePanel?: boolean; hideDataSettings?: boolean; + defaultDataKeysFunction?: (configComponent: any, configData: any) => DataKey[]; + defaultLatestDataKeysFunction?: (configComponent: any, configData: any) => DataKey[]; } export interface WidgetControllerDescriptor { From 9b5bea618c6b3b9fa7e4efe9d074b991342f944a Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Wed, 18 Oct 2023 17:04:42 +0300 Subject: [PATCH 201/267] UI: Rename widget type to widget --- .../import-export/import-export.service.ts | 6 +-- .../save-widget-type-as-dialog.component.html | 4 +- .../pages/widget/widget-type.component.html | 6 +-- .../widget-types-table-config.resolver.ts | 22 ++++----- .../widgets-bundle-widgets.component.html | 4 +- .../app/shared/models/entity-type.models.ts | 14 +++--- .../assets/locale/locale.constant-ca_ES.json | 4 -- .../assets/locale/locale.constant-cs_CZ.json | 4 -- .../assets/locale/locale.constant-da_DK.json | 4 -- .../assets/locale/locale.constant-de_DE.json | 4 -- .../assets/locale/locale.constant-el_GR.json | 4 -- .../assets/locale/locale.constant-en_US.json | 46 ++++++++----------- .../assets/locale/locale.constant-es_ES.json | 30 +++++------- .../assets/locale/locale.constant-fa_IR.json | 4 -- .../assets/locale/locale.constant-fr_FR.json | 4 -- .../assets/locale/locale.constant-it_IT.json | 4 -- .../assets/locale/locale.constant-ja_JP.json | 4 -- .../assets/locale/locale.constant-ka_GE.json | 4 -- .../assets/locale/locale.constant-ko_KR.json | 4 -- .../assets/locale/locale.constant-lv_LV.json | 4 -- .../assets/locale/locale.constant-pt_BR.json | 4 -- .../assets/locale/locale.constant-ro_RO.json | 4 -- .../assets/locale/locale.constant-ru_RU.json | 4 -- .../assets/locale/locale.constant-sl_SI.json | 4 -- .../assets/locale/locale.constant-tr_TR.json | 4 -- .../assets/locale/locale.constant-uk_UA.json | 4 -- .../assets/locale/locale.constant-zh_CN.json | 4 -- .../assets/locale/locale.constant-zh_TW.json | 4 -- 28 files changed, 58 insertions(+), 154 deletions(-) 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 e91375e75e..f279972101 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 @@ -298,13 +298,13 @@ export class ImportExportService { } public importWidgetType(): Observable { - return this.openImportDialog('widget-type.import', 'widget-type.widget-type-file').pipe( + return this.openImportDialog('widget.import', 'widget-type.widget-file').pipe( mergeMap((widgetTypeDetails: WidgetTypeDetails) => { if (!this.validateImportedWidgetTypeDetails(widgetTypeDetails)) { this.store.dispatch(new ActionNotificationShow( - {message: this.translate.instant('widget-type.invalid-widget-type-file-error'), + {message: this.translate.instant('widget-type.invalid-widget-file-error'), type: 'error'})); - throw new Error('Invalid widget type file'); + throw new Error('Invalid widget file'); } else { return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html b/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html index 2ce7acd7e1..7588d1d8f5 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/save-widget-type-as-dialog.component.html @@ -17,7 +17,7 @@ --> -

widget.save-widget-type-as

+

widget.save-widget-as

- widget.save-widget-type-as-text + widget.save-widget-as-text widget.title diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html index 19309e8660..9db9780b70 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-type.component.html @@ -20,19 +20,19 @@ [disabled]="(isLoading$ | async)" (click)="onEntityAction($event, 'edit')" [fxShow]="!isEdit"> - {{'widget.edit-widget-type' | translate }} + {{ 'widget.edit' | translate }}
diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-types-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-types-table-config.resolver.ts index 8fcf76f1fe..0363aa6117 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-types-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-types-table-config.resolver.ts @@ -87,13 +87,13 @@ export class WidgetTypesTableConfigResolver implements Resolve true, onAction: ($event) => this.addWidgetType($event) }, { - name: this.translate.instant('widget-type.import'), + name: this.translate.instant('widget.import'), icon: 'file_upload', isEnabled: () => true, onAction: ($event) => this.importWidgetType($event) @@ -102,13 +102,13 @@ export class WidgetTypesTableConfigResolver implements Resolve true, onAction: ($event, entity) => this.exportWidgetType($event, entity) }, { - name: this.translate.instant('widget.widget-type-details'), + name: this.translate.instant('widget.widget-details'), icon: 'edit', isEnabled: () => true, onAction: ($event, entity) => this.config.toggleEntityDetails($event, entity) @@ -117,18 +117,18 @@ export class WidgetTypesTableConfigResolver implements Resolve this.exportWidgetTypes($event, entities) } ); - this.config.deleteEntityTitle = widgetType => this.translate.instant('widget.delete-widget-type-title', - { widgetTypeName: widgetType.name }); - this.config.deleteEntityContent = () => this.translate.instant('widget.delete-widget-type-text'); - this.config.deleteEntitiesTitle = count => this.translate.instant('widget.delete-widget-types-title', {count}); - this.config.deleteEntitiesContent = () => this.translate.instant('widget.delete-widget-types-text'); + this.config.deleteEntityTitle = widgetType => this.translate.instant('widget.delete-widget-title', + { widgetName: widgetType.name }); + this.config.deleteEntityContent = () => this.translate.instant('widget.delete-widget-text'); + this.config.deleteEntitiesTitle = count => this.translate.instant('widget.delete-widgets-title', {count}); + this.config.deleteEntitiesContent = () => this.translate.instant('widget.delete-widgets-text'); this.config.loadEntity = id => this.widgetsService.getWidgetTypeById(id.id); @@ -147,7 +147,7 @@ export class WidgetTypesTableConfigResolver implements Resolve { - this.config.tableTitle = this.translate.instant('widget.widget-types'); + this.config.tableTitle = this.translate.instant('widget.widgets'); const authUser = getCurrentAuthUser(this.store); this.config.deleteEnabled = (widgetType) => this.isWidgetTypeEditable(widgetType, authUser.authority); this.config.entitySelectionEnabled = (widgetType) => this.isWidgetTypeEditable(widgetType, authUser.authority); diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html index 2d95fd1fdb..bf1818faf1 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html @@ -54,14 +54,14 @@ diff --git a/ui-ngx/src/app/shared/models/entity-type.models.ts b/ui-ngx/src/app/shared/models/entity-type.models.ts index d7858965d7..5c9390f80f 100644 --- a/ui-ngx/src/app/shared/models/entity-type.models.ts +++ b/ui-ngx/src/app/shared/models/entity-type.models.ts @@ -271,14 +271,14 @@ export const entityTypeTranslations = new Map Le type de widget associé a probablement été supprimé.", "no-data": "Aucune donnée à afficher sur le widget" }, 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 24555cc332..f2e1ffa240 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -1488,11 +1488,7 @@ "settings-schema": "Impostazioni schema", "datakey-settings-schema": "Impostazioni Data key schema", "javascript": "Javascript", - "remove-widget-type-title": "Sei sicuro di voler rimuovere il tipo di widget '{{widgetName}}'?", - "remove-widget-type-text": "Dopo la conferma il tipo di widget e tutti i suoi dati non saranno più recuperabili.", - "remove-widget-type": "Rimuovi tipo widget", "add-widget-type": "Aggiungi nuovo tipo widget", - "widget-type-load-failed-error": "Caricamento tipo widget fallito!", "widget-template-load-failed-error": "Caricamento template widget fallito!", "add": "Aggiungi Widget", "undo": "Annulla modifiche widget", diff --git a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json index 875b0a8266..c65928e452 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ja_JP.json +++ b/ui-ngx/src/assets/locale/locale.constant-ja_JP.json @@ -1331,11 +1331,7 @@ "settings-schema": "設定スキーマ", "datakey-settings-schema": "データキー設定のスキーマ", "javascript": "Javascript", - "remove-widget-type-title": "'{{widgetName}}'?", - "remove-widget-type-text": "確認後、ウィジェットのタイプと関連するすべてのデータは回復不能になります。", - "remove-widget-type": "ウィジェットタイプを削除", "add-widget-type": "新しいウィジェットタイプを追加する", - "widget-type-load-failed-error": "ウィジェットタイプの読み込みに失敗しました!", "widget-template-load-failed-error": "ウィジェットテンプレートを読み込めませんでした!", "add": "ウィジェットを追加", "undo": "ウィジェットの変更を元に戻す", 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 b401c3b594..28458f0a70 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ka_GE.json +++ b/ui-ngx/src/assets/locale/locale.constant-ka_GE.json @@ -1578,11 +1578,7 @@ "datakey-settings-schema": "მონაცემტა გასაღები პარამეტრების სქემა", "javascript": "javascript", "js": "JS", - "remove-widget-type-title": "დარწმუნებული ხართ რომ გსურთ ვიჯეტის ტიპი '{{widgetName}}'?", - "remove-widget-type-text": "დასტურის შემთხვევაში ვიჯეტი და მასთან ასოცირებული მონაცემები დაიკარგება.", - "remove-widget-type": "ვიჯეტის ტიპის ამოღება", "add-widget-type": "ახალი ვიჯეტის ტიპი", - "widget-type-load-failed-error": "ვიჯეტის ტიპის ჩატვირთვა ვერ მოხერხდა!", "widget-template-load-failed-error": "ვიჯეტის შაბლონი ჩატვირთვა ვერ მოხერხდა!", "add": "ვიჯეტის დამატება", "undo": "ვიჯეტის ცვლილების გაუქმება", 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 a5660c5ceb..09cea16190 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ko_KR.json +++ b/ui-ngx/src/assets/locale/locale.constant-ko_KR.json @@ -2213,11 +2213,7 @@ "datakey-settings-schema": "데이터 키 설정 스키마", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "'{{widgetName}}' 위젯 타입을 삭제하시겠습니까?", - "remove-widget-type-text": "위젯 타입 및 관련된 모든 데이터를 복구할 수 없으므로 주의하십시오.", - "remove-widget-type": "위젯 타입 삭제", "add-widget-type": "새로운 위젯 타입 추가", - "widget-type-load-failed-error": "위젯 타입을 로드하지 못했습니다!", "widget-template-load-failed-error": "위젯 템플릿을 로드하지 못했습니다!", "add": "위젯 추가", "undo": "위젯 변경사항 취소", 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 c489cd3402..63e7fb6db2 100644 --- a/ui-ngx/src/assets/locale/locale.constant-lv_LV.json +++ b/ui-ngx/src/assets/locale/locale.constant-lv_LV.json @@ -1493,11 +1493,7 @@ "settings-schema": "Iestatījumu shēma", "datakey-settings-schema": "Datu atslēgas iestatījumu shēma", "javascript": "Javascript", - "remove-widget-type-title": "Vai esat pārliecināts, ka vēlaties noņemt logrīka tipu '{{widgetName}}'?", - "remove-widget-type-text": "Pēc apstiprinājuma logrīka tips un tā saistītie dati nebūs atjaunojami.", - "remove-widget-type": "Noņemt logrīka tipu", "add-widget-type": "Pievienot jaunu logrīka tipu", - "widget-type-load-failed-error": "Neveiksme ielādēt logrīka tipu!", "widget-template-load-failed-error": "Neveiksme ielādēt logrīka paraugu!", "add": "Pievienot logrīku", "undo": "Atcelt logrīka izmaiņas", 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 e8a105bcc2..51c8579980 100644 --- a/ui-ngx/src/assets/locale/locale.constant-pt_BR.json +++ b/ui-ngx/src/assets/locale/locale.constant-pt_BR.json @@ -1803,11 +1803,7 @@ "datakey-settings-schema": "Esquema de configuração de chave de dados", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "Tem certeza de que deseja remover o tipo de widget '{{widgetName}}'?", - "remove-widget-type-text": "Após confirmar, não será possível recuperar o tipo de widget e nenhum dado associado.", - "remove-widget-type": "Remover tipo de widget", "add-widget-type": "Adicionar novo tipo de widget", - "widget-type-load-failed-error": "Erro ao carregar tipo de widget!", "widget-template-load-failed-error": "Erro ao carregar modelo de widget!", "add": "Adicionar widget", "undo": "Desfazer alterações de widget", 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 8ea796cbc3..67f8d839be 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ro_RO.json +++ b/ui-ngx/src/assets/locale/locale.constant-ro_RO.json @@ -1561,11 +1561,7 @@ "datakey-settings-schema": "Schemă setări chei date", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "Sigur vrei să ștergi tip widget '{{widgetName}}'?", - "remove-widget-type-text": "ATENŢIE! După confirmare, tipul de widget şi toate datele aferente acestuia, vor fi șterse IREVERSIBIL!", - "remove-widget-type": "Şterge Tip Widget", "add-widget-type": "Adaugă Tip Nou Widget", - "widget-type-load-failed-error": "Eroare încărcare tip widget!", "widget-template-load-failed-error": "Eroare încarcare şablon widget!", "add": "Adaugă Widget Nou", "undo": "Anulează Modificări Widget", 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 70aa4b3a23..5e15a3496e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-ru_RU.json +++ b/ui-ngx/src/assets/locale/locale.constant-ru_RU.json @@ -1599,11 +1599,7 @@ "settings-schema": "Схема конфигурации", "datakey-settings-schema": "Схема конфигурации ключа данных", "javascript": "Javascript", - "remove-widget-type-title": "Вы точно хотите удалить виджет '{{widgetName}}'?", - "remove-widget-type-text": "Внимание, после подтверждения тип виджета и все связанные с ним данные будут безвозвратно утеряны.", - "remove-widget-type": "Удалить тип виджета", "add-widget-type": "Добавить новый тип виджета", - "widget-type-load-failed-error": "Не удалось загрузить тип виджета!", "widget-template-load-failed-error": "Не удалось загрузить шаблон виджета!", "add": "Добавить виджет", "undo": "Откатить изменения в виджете", 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 f2943e6145..4fded7d020 100644 --- a/ui-ngx/src/assets/locale/locale.constant-sl_SI.json +++ b/ui-ngx/src/assets/locale/locale.constant-sl_SI.json @@ -2214,11 +2214,7 @@ "datakey-settings-schema": "Shema nastavitev podatkovnega ključa", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "Ali ste prepričani, da želite odstraniti vrsto pripomočka '{{widgetName}}'?", - "remove-widget-type-text": "Po potrditvi bodo vrsta pripomočka in vsi povezani podatki nepopravljivi.", - "remove-widget-type": "Odstrani vrsto pripomočka", "add-widget-type": "Dodaj novo vrsto pripomočka", - "widget-type-load-failed-error": "Vrste pripomočka ni bilo mogoče naložiti!", "widget-template-load-failed-error": "Predloge pripomočka ni bilo mogoče naložiti!", "add": "Dodaj pripomoček", "undo": "Razveljavi spremembe pripomočka", 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 50758fb1eb..e9be2e691a 100644 --- a/ui-ngx/src/assets/locale/locale.constant-tr_TR.json +++ b/ui-ngx/src/assets/locale/locale.constant-tr_TR.json @@ -2831,11 +2831,7 @@ "image-preview": "Resim Önizleme", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "'{{widgetName}}' isimli gösterge türünü kaldırmak istediğinizden emin misiniz?", - "remove-widget-type-text": "UYARI: Onaylandıktan sonra, gösterge türü ve ilgili tüm veriler geri yüklenemez şekilde silinecektir.", - "remove-widget-type": "Gösterge türünü kaldır", "add-widget-type": "Yeni gösterge türü ekle", - "widget-type-load-failed-error": "Gösterge türü yüklenemedi!", "widget-template-load-failed-error": "Gösterge şablonu yüklenemedi!", "add": "Gösterge ekle", "undo": "Gösterge değişikliklerini geri al", 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 10d998d031..da3b6ecaee 100644 --- a/ui-ngx/src/assets/locale/locale.constant-uk_UA.json +++ b/ui-ngx/src/assets/locale/locale.constant-uk_UA.json @@ -2170,11 +2170,7 @@ "settings-schema": "Схема налаштувань", "datakey-settings-schema": "Схема налаштувань ключів даних", "javascript": "Javascript", - "remove-widget-type-title": "Ви впевнені, що хочете видалити тип віджета '{{widgetName}}'?", - "remove-widget-type-text": "Будьте обережні, після підтвердження, тип віджета і всі пов'язані з ним дані стануть недоступними.", - "remove-widget-type": "Видалити тип віджета", "add-widget-type": "Додати новий тип віджета", - "widget-type-load-failed-error": "Не вдалося завантажити тип віджета!", "widget-template-load-failed-error": "Не вдалося завантажити шаблон віджета!", "add": "Додати віджет", "undo": "Скасувати зміни віджета", 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 b8c0a36fe0..5df0238594 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -3965,11 +3965,7 @@ "latest-data-key-settings-form-selector": "最新值数据键设置表单选择器", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "确定要删除部件类型 '{{widgetName}}'吗?", - "remove-widget-type-text": "确认后,窗口部件类型和所有相关数据将不可恢复。", - "remove-widget-type": "删除部件类型", "add-widget-type": "添加部件类型", - "widget-type-load-failed-error": "无法加载部件类型!", "widget-template-load-failed-error": "无法加载部件模板!", "add": "添加部件", "undo": "撤消部件更改", 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 0091acbb61..85c9181ae8 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_TW.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_TW.json @@ -3390,11 +3390,7 @@ "latest-data-key-settings-form-selector": "最新資料鍵設置表單選擇器", "javascript": "Javascript", "js": "JS", - "remove-widget-type-title": "您確定要刪除部件類型 '{{widgetName}}'嗎?", - "remove-widget-type-text": "確認後,窗口部件類型和所有相關資料將無法恢復。", - "remove-widget-type": "刪除部件類型", "add-widget-type": "增加新的部件類型", - "widget-type-load-failed-error": "無法加載部件類型!", "widget-template-load-failed-error": "無法加載部件模板!", "add": "增加部件", "undo": "復原部件更改", From 84f27b1d456006fc4e711755e94590391e1c500e Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 18 Oct 2023 17:50:38 +0300 Subject: [PATCH 202/267] UI: Fixed position of help icon in custom date config of card widgets --- .../settings/common/date-format-settings-panel.component.html | 2 +- .../settings/common/date-format-settings-panel.component.scss | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html index ee332924f0..3a2d9f78b9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html @@ -21,7 +21,7 @@
date.format
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss index ec6a762966..784b4fbeb4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss @@ -51,7 +51,6 @@ .mat-mdc-form-field-icon-suffix { display: flex; align-items: center; - line-height: normal; } } } From e1f034500fa9ada62a7f142d2e712e1a8706d3e5 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 18 Oct 2023 18:02:49 +0300 Subject: [PATCH 203/267] UI: Outdoor Environment: Temperature widgets --- .../widget_bundles/outdoor_environment.json | 20 +++ .../horizontal_temperature_card.json | 28 ++++ ...ntal_temperature_card_with_background.json | 28 ++++ .../simple_temperature_chart_card.json | 31 +++++ ...emperature_chart_card_with_background.json | 31 +++++ .../system/widget_types/temperature_card.json | 28 ++++ .../temperature_card_with_background.json | 28 ++++ .../widget_types/temperature_chart_card.json | 31 +++++ ...emperature_chart_card_with_background.json | 31 +++++ .../widget_types/value_and_chart_card.json | 2 +- .../DefaultSystemDataLoaderService.java | 1 + ...gated-value-card-basic-config.component.ts | 121 ++++++++++-------- .../pages/widget/widget-editor.component.ts | 4 +- 13 files changed, 332 insertions(+), 52 deletions(-) create mode 100644 application/src/main/data/json/system/widget_bundles/outdoor_environment.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_temperature_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_temperature_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_card.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json diff --git a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json new file mode 100644 index 0000000000..a21eaf65f0 --- /dev/null +++ b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json @@ -0,0 +1,20 @@ +{ + "widgetsBundle": { + "alias": "outdoor_environment", + "title": "Outdoor Environment", + "image": null, + "description": null, + "externalId": null, + "name": "Outdoor Environment" + }, + "widgetTypeFqns": [ + "temperature_card", + "temperature_card_with_background", + "horizontal_temperature_card", + "horizontal_temperature_card_with_background", + "temperature_chart_card", + "temperature_chart_card_with_background", + "simple_temperature_chart_card", + "simple_temperature_chart_card_with_background" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json b/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json new file mode 100644 index 0000000000..153195a499 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_temperature_card", + "name": "Horizontal temperature card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAsVBMVEUAAADf39/u7u7x8fHr6+vl5eXf39/f39/r6+vq6ur////z8/MjTMc+Ys7IyMjj4+Pk6fitvOqRpePPz8/x8fGtra2QkJDCwsLy9Pv5+fnI0vHV1dW2trZYWFg9PT3n5+cwV8vt7e1aeNXW3fV1j9zb29tog9laedW8vLxmZma6x+5MbtGCgoIvLy88PDyfsOeDmt+enp50dHRKSkrU1NSRpuNMbtIhISHd3d0xV8qdnZ2QKY5sAAAACnRSTlMAIN/vz6AQML+/B+y1FwAAA4lJREFUeNrt2glzmkAYxnHTptfLsssNCgoqGPCsR8/v/8H6LjTVaqsZ66TGeX4ZDbDMZP+yDpPRFgAAAAAAAAAAAAAAAAAAAAAAAAAAAMBzenv3wr1tae8+GC+dd3/Xat29phvw+q71hm7Cm9Y93YRXrVd0ExBybRBybRBybRBybW47ZGiKPKL/IurY9pAalm13dofs8a8te2zRrr+EmOZIOLTVZT4d4cV0GXYm2Mgi9lEwk6salpmJSZ3BA81Jp0Is4TjZgLaU31UexYqUkiqWPG/eJk8SxbHnSUX+WilFkmJ+5vGzdYQYOLkQD7z9SYiPjim+RdTIzcgS+ppM+KSPI26MnhASmQPaIbtE3elaBvNpb9VdynUwl/F82qVeFfe+z+V0LgOfvvCunK6qJZ3roU5whLCITL0oooyfG6MRUWYT2ULYepJ65HTIMNsPUbOgmgYB9cgPeDdYrqpg5vV4bNrz+UATomgWrCo6lxCL+u+Ljr44Q72+OK1hi9FDVgfmxHjEfELI4jCkp5S3DVktp0uleM+bedVvIXp5ncuyomaBWTQWgthiO117MOK0SPD60obOU64IHS6tYF3Jx5BZtVZqXa10yLya+d7cl71qpkO+97pL+je5GNQrqLkO5sHbqENbJ0LMBzGgfd5Ol7dzwGse3va8f8PvcusyIUPBPtPfqYAuzBSsQ0yvKYcuEzIR2oKe0cBkHWLDjDuOhAyfHmKL2reIHvXpj/oG7Wi3+ZHSP7JM7tgJcfaXRvT4Eo/z/ETISDTG9ChpZs3T3Gx4tvqH2/puyr/aZTP92NcnuFQPGf12nXlOR/5zq3nlR2L0x3uNHvl8IiQXjc5uSOom7cRVUhKFRmj4sfwqwzRWYT8xEtclfdjw9YarSqOUxUaW7XM6JtsFntc59uHd/1NzxewTIQvRiHZDvrqJUci0KJqQhEI3LVJ3UxJXuXEd0ncNHbJJiiItSnLTM+7sIjO1vH7Tmw+ZMGmfowdMwcknQqKJ0BzahoSyKH0jCeM0JCpC3/C5IyzT0k0oMUpX1SHtRHIIH2uXYRGHCZ0T0hjwjm3qDYv2NQOZQ6dCKMozMbHpmOOTbBdS0QVYw+hvA9x3GHKGPh1l9Ol53fp/iC8RQq4NQq4NQq4NQq7N/e18PH0zXxho3d17xkv3/t0tfakGAAAAAAAAAAAAAAAAAAAAAAAAAAAA4Jn8AJ01hSMevW95AAAAAElFTkSuQmCC", + "description": "Displays a latest temperature telemetry data in a horizontal layout.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal temperature card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json new file mode 100644 index 0000000000..1c711e7e1f --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_temperature_card_with_background", + "name": "Horizontal temperature card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest temperature telemetry data in a horizontal layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal temperature card with background\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json new file mode 100644 index 0000000000..f89e7ec47b --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_temperature_chart_card", + "name": "Simple temperature chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays historical temperature values as a simplified chart. Optionally may display the corresponding latest temperature value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'temperature', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Temperature\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"thermostat\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"°C\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_temperature_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card_with_background.json new file mode 100644 index 0000000000..9c8d069c8e --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_temperature_chart_card_with_background", + "name": "Simple temperature chart card with background", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAC91BMVEUAAAAHBwcQEBDY0ts5UE+mqrhMW1NEUk7R0dpWZFnX1uObobbw8PDW0+D7+vr8+/v5+fr4+Pn39vjz8vT29fb08/X19PYjTMf9/fvx8fPv7+/w8PHv7Obt7e/q6+zt7ezp6ezo6Orm5+jz8vLr6+3u7u7s7O7f4N/19PDX1uH29fHs6+zn6Onp6Ojv7/Hx8e/l5efs6+bn6Obe3eTn4uXi4ubm5uXb2uQhISHu7fHi5OXg3+Xy8PHk4OTk5uXt6+Xa2ePq6erp6ebs6urExMTg3uPd3OLZ2OLq6ejk4+jh4uLh4Obk5OOtqoTGw9Hw8PPc3d2pqakgICCppoPm5el/gYCxrIfp4+Omon9lcGgvLy48PDzp5tzs6+6Oj41xcXFrc2dXV1dzjdqJiIWEh4CvqX+ppX7d2+Xd399RYVzj4t/Q0NjX19ZNXlgxTlDt7Oc+Ys6OjYDg39zl4tnT09G2tsS1sIo+VlXh4eCzrYEqR0lYd9Ourr23so6knn9caWTX19za2tq+vcqiooB7fXljbmJHXVxGWVXHzM3CuJaXlIyLi4udnH1UZ2FWYlwiREjg5fTEwMyyrY5LaW1cZl5WVlbw7ubb2t65uce8spCRj4ipo4eBgnpydWjPy9S7s4mtp4i3sIR7g3aEhnVze21Za2k0VFchISCpuOfo5OWamZmvqY13gHB5fHAlSlHNz8+ZloWTj3ju8PfFz+6Oo+DKxdKxs8Ftd247OzuKiHyfnnkdPkOel4+WkYGCg25KSkn39vLQ1dR2e3ZndnA9W1zBv868u8SqrLq4rI+XlXpteXeLi3VdcHErT1SdruSeo7TKvJzAt5GjnYtheoBLZWKCmd7LvKO/tJZkZGOQpOFVdHvKy9MwV8qkprGooperpJBmgtdKbNCiqbinpqain5W+wMi3trauqJZ/iYpISEnT2vGOlaamoY5ygYRMbdGWna0tLS2Po+GWmqKCjJ2Nod+JkZ63xOqAltwwVsrGxcWgoafPy7qurK2iedcZAAAADnRSTlMABwX+/vy5JCDvv7+vr1FMo1QAABuiSURBVHja7JS9ittAFIUXQiDk5wVGzIwkNBOM5I1AOMYWBA/GcmQHZwu1qR2YtIYUKZRUaVNpK7/F7htkU+4DmG0WXLlYSEifc6Vd/BCZb0ZXknGhj3PvnDgcDofD4XA4HA6Hw+FwOBwOh8PhcPx3PHn2+HxztthdHu6y7erH99re7Cum+qPzq5yxVHPuR5JLpqIpHs/2N7e3u92Xy8330+hDOSttntV53TRxHIt44NuiGovIjyIRUQ0iYSLhBybxAz+4J0mCIAyqMKzKKk0rusqyKgeDshwsl0tc+SBfYhHZOi+G2TDLhi2TCV1zbNDrYRMvnsDD1Ha7uvj15cvl379WK++UscnNue+rtLmdT5XSg+UZV1IpZZTinDOVfru2q/pit6prW9d5oxMpNXnI/qyKhIjjSGsBFyjgVfg+THwCLnisoJKE2KCCQ5liQaKDXMgCJYNHlhcoxHA9Ga47F2hM5r35pPeAfXLy3GPGe9kMAnu97/05XL3k76Pp1B5+aWTwrfGUx04bptSINoCRUHktEZJ8G3IV4B5rjq+Xmje11lFrIDRugILxSUUEx0wSWmFLWoESoBxFiJxEiIxYr7HbSIak0YXSO/L0JDaMG2aQ9CyvN7fz7dWvm73d2f31xorTr5Yrpj4yxUZMjVuPWCKAwNaFMFxz6ZMS11pD56wxOsKKQ7RXZwInIyBxTycBkAct6iwCIgMSKR9EBkgkgwpF0omgt7C7TIakAp+jiD3xTBoLo8J4GmjTvz5cXPg839mNtY+ubr4U2Q/OEgTCcAnG+IKZ1+guUBR1yvQoQbeNJOC6SuEzRY+VaaS7SCgc8mklyAP1XgRGEGlTSUtSIVqVViNvwX1WtC6okEAeVLoZoQl5YH7iedLE8qMSfSH6b+TmTynMh6ap65EYpOOru7vL85ozoGLeN+F44acSo6LGkrOwqT+8M4qPOKKKTY6/6FiaM19jZNBkhjTgRJjOwyeJdlMiVSdCJu2UpIMWEkGlKSEhiAwzUBRD5JKtIUMepHF0OXnFmIz7bwQDnmLj+vd+NEu8023Y/vJ2tbk7DxgLlts3/VjpSCzQa1InHCODd2uLER9ziYRWjdKaR2lQCTQaPDQUYphEPtqri8UEwO9UEEgAC/KoyKPqeosgDSwywSZQYUB5EJM2lF7r8iCCj/WESGSIB+b1map+H+z7VyxMZp8ZIV8Vh+ufvp3AFXOOowljP5MKKfSlerNYbHH8FvWnZfBxts0K28x+pKmBC/VWjIIb8AlMy0Ms4X1zJTiyiBJUlMqR7gTuji60Vr5eQ6aFTNohgc5RBCb/aDGfF6eBMAz3L5hJay1ui0atJeKiEawatcKKaf2JErEICbbkpOBNKnjUvXrysOhpr8v24k289aRXrwuLF0VBPHj25vvNNP1sYpI24pPJJJlN7Tz7zpdtPXy+3jjUaKzWn13qnrz74/Pp83dR3ydOPjzZMI/X6+e/rv/89Pb16ydvP75df/th89GtD+u7L3d317++X3/0aHPz18tH56wD5vmT+1dR+auryOPkeVQ7mIpELuggolSiJxdU0Kkq0R6qmxX9Da0CetggMk0FmaApERQLidh1u3HcqtvH63sr5ZVKbW/t3JFa7VK1DHBVqVRq5UqrhmMZ28pKY2XPwfvVlb24whDAT1ZwhkYYhkGdOi3/nUoG1Uq1Vq1Wa0AfwN7pAW3GHuy37+taIZG10k386u2r5rXdZ3swB3oX/AOYlGEIwojQc5y71AN8j1BIamkYgu5PJ9WdJqbaHHtoeVEma1dKzzff3Hqyu7l+sGYAMqkCEpm99V+ZefEEpx6SSDfBng1nGc8xGeZB5KGq5WwJK2vlUqvesMv6LXBvlAhjMHzOHhoWEanQ69EVygRQInOx7L2i/sIrERvlfqbRqJcFUJHERdhG5InIWVc8Eoo61YUdtMga1T3KX4nY9cstJaJN8HMWkcmJpHrkm/A/kZdKikpCpLcGIPMAInanUwcGLe64iJQ8Q4Y14kiAPtckTyU1lIRIrwcNrK9Sp2E37DpyMSSYRUL58sToOCdjiBRk9gBXCli65hEIupjIK/xtfHC2R8XeUMsLk2UTvGDqIahFpEx+elv0glwTjkQsE0llFgsaJ7LW613pQQQSCj0fJaJewolQl+Eio+nHF1V+pYgCmaDRxiKvSAYiAJGoRNiERUC2SFpgMjMTUlAuy6tQx4lElC43Ox1aWx1DKmKRgCwVutS7ElouERJRZ5lkeECkC4dTtJfqxzudDhJhEW0y/sKZxEikgQMri6VQ75HtgT0Gq9R6pxS9bqljbjcbtLxIhCN58e7dC13van7fPIUkuBT0QXIyBFsuHEw2cZMKGidyCt8g0XVLzeZqqwNsEmGTjRcbG9HiwthOOHEmYSglw2HEhrR86C0cSr5JUgSNqHW7F7rdbo8SQY2YJr6qGjJCi4xJhMvEdVwJRq4lpdUyXQunppCWOVLjLXckhWmZuLDULU7fFJaJISEsMcKJ6+Z+aMlQSvkbX9MWoASPJh5bnSbNliPZeLHDInImMvQDfyTDIPD9YeAHpnSCwJm0pOcHzgD3+I4c+KEzFoHj9y3Hw5BlOYHjWnjJZDUlEB2KyM+ENTiRKSUbq4pS6bCIJJGd4UaZI5mKeI4lh6EMJ7LlDzE0kk4fB08GZGG5MJDDb7LvCwkviAglMjDNcCIsf1x4fSVVsLoikQtaxKZMpjXCJht37nyHCOClRYEMhxNfUrEEmCiGIIFT1wmHO47nwlOO+juBQyJiloiLy8lw6PdTNXSXb8Ie+lC7cEGZXCQRpKETYYR3B4wNFhFaJPBAUmTkDDBukYiFJdV3pEqERYSzgxvczJInMjSSZYKt1r1x4WIXGz21mp1m046JhA5EvhsKQZCIkB4WkzWKRJ6SSB/z/dby+9L8JklkhPuGjhT+QJiQGU9FwokpPDP/6UWHvC8p7FGuXoSE2kvKI56IDB1HibCJLva+g6KeE5kEPq483/fDFomYeAZMHFOGUBw6ONUiFoYDK1Mj2rWJWOgrSo0sIhFAZTInMnacrS2PRYBlCvX4bUnZUo9gtaMwRtHjFwMSuCNBP3QxbQzSrUiCztUhN5SsBRYHiVyHxdOLWsQmlAjjheFY/CkiaU+CMkgidKebENQtTPZT2IiLQENT0oFARiQ/UcVM5F8YujIGT1/rU7+MhgC5X4BZBLAIkSMC5HIIhlUW9clgKRGeSUERoTtsRcj8poJYkiLtdulYZJIU0RQRIYGCmfACWySUavtimzwgchRhcCJJFUbq2dHoYpHwf6AuTfYHSFapQAEaKhFlchQiiy/0RWOJ3IuR8yHS0CKESqR5FDRBvggjl6GoBlpuKNXt9pQS8iARTiTGv4sgmOIq1JXnjgquEQ3VSET67P41EKm25bMxyiK5zS0viEwj2Y5EbIhkIViJRfYtlUqxlUaTnzNB48VVVRIzkWOcSA4pceQa6UCW8DAfUySsgcZGsEADUSLbnAiJ/DfEkrVvDoKtra2JFyXCW3SICqV6b3t7KoI0NHO/VlwUIz/QqKUz8rfCgTeYbAWWwWlwJ5AGNSVCEmRSOnbs6DHsEClAEWGWSPUIXEF4AUwMzoI3ZaFF7rXbaG2IAFUkYt8+mhb67GlirLjEIh8o+QuY5YfxMok6jCMUiAAl85tzswdxIojieCC97kbPaOEHfqC4iLYWFpLUd7nBNCt3S1KJNkEshDQmWAhpNkW4q2yzpDlITtjONLFMFzCQIhIQkuI4GxEr/28+9iWXXYP+1szMnnvc+917s7vZzKXIg7gPESXB4Asx4ZIwtv+CL/YUfmx2dtu70dPU/XZepSRmqkDE1iJPUFtKhBqKDshApRENgWxWRFhwM+zMGZEmul13KT3nt1dOu2hxLizalAd6XVoGiOjzrxTAi3OhLYwZa8RZJJucuxyTFZ7+smXutj2LabmO/Tf6yuIlMqJE0MifF2VAh29c1GZgYf7KZg++u49kjAVj7bbfLN1M5cX3ZAvOyJMnr/Vkxz8KNaoqoPaH1UrlpNzTRud7U9r1Oc5hZRLt+qMTeXCiCURka0SokeT39/PUUw5C0ohwW3rtSN9Gb0b6aVBfirw8eJdOpyEClIiuGg0N/EpWMVJeY707NqGNs5NKttJVTlnNaFkDHsaEQpUKqudqKrUBTrXghSiqKDUNUeB1KqYBfdVtvS0cwEKK9LWKLn+5GeAxGY2rCG5IuwEG0/EUrfmtk8QoGygnHFyenqArL08IHiXx3N29fn3X/QyTa3O3AAnmqWhEY5ZBi3UmeN1KG1J9XVvq9MuQFAKv+OhH6LXXUIVc1cVEMfdkghYmUcGEPJMvgp2SvPswWNZMPUD77oqvX10xy6zSOr2YzCUl8vFV+lWqbzKi0iExBYZUBLTbRZDd85d78KH/7k5oV40qPrzooGqUCPbk+JlSu1TcL7U/O5bGCVtqUhS8eVg8YgUVa1505HonvGLYSWO52CfwERnRKTlHHnx6ogYZWKgKkpEPTfmjuH7quY5yIrtzPg7Rk35BR59LoNjet0BHeGZKN8SRba8t2mJap0cm7Js31ZIt5jE0iO1tOdn7ZMLvMvSL8VUqRmaWl6nEFEH12zFF/TObPTHBBkGwLmJJXhiBhsihhUAh9M5YaEwKaqFo1LYubX15fyrEqXdEi84uGB5vG3RpoYFIEgi8rLof6KTR8Zk4j1FPm58g2DORtyUF0eDTEsMSUSVt1Twh5q1QuF6j4YXCq11grlIyWGTD+5EF6sfXIvIO6UesSDlZAAoKL+RJLKdDXnhrmWAHTQ2fzHqdm5SIZw0RdlZEmlrk3q17DyUssuhJ9Fw979PJioZlE/9xgoi510t4XItoXRM2Skp4s9lXERaUAmMsGC4mUMP3fIhEoDEYSJGHWOP0EM3S5+zVLFHRIXbhMaJBsghCJ5GkJ5t8gcMdRyYy8Vwh3MaDFYe1dLAE8zucRyIfZWk1IULLw7FM33EsE9aqSPcb/a5jRSyGRKYswZABUxQPlmfDwcFaKmSznItYHlFzBdtjeJDIYJC6cz3nXM/lnJwdiXR9SRT9t64ayjlOhUNnLWuVAOZGAGXZ5TQsM2+xxQpkwCyXVCJXiL1tKq1ms15P7Tk3bjtOznHs9UmKqOmi3tWLYuk6YhF0HTkzkX26eCiPBQ0zcRREx0hwLVEa/tUCyVDsDer1w/p2s9lM7e1h7boDbI4L6L0f8PAtTQ/JkQPMGt8+81lrFelStRTgsEwsM3G0YhHHhqrSIoYbgwFU6s3Dw9QN+gsi/L1NLhNJZCRwYQ/FL9xF4ZAhIrWZKPxJLwMW0AziF1mHYaLFFjYQk4xkj52dnRtUVYNDqPwh3Fx/WwrjOH7e+APELVToavQFp5lGmlSotIukWKIuExNmMS+QxuLSkehGWUS3Spjbmro0LstopvamTEaCpXUfm6yJuAQLe7MQl7i+8P09F4+2R3x6+pynp6f8Pvv9nidd+GnuIljo7qLzI+kbvqpgUmkbg5DXcB4OZwbP1rR9HcMilQZyNayhr8afP6PschIiv6xibFr8ptACBjhyMYpdzZQHRGDRcvAgsqLNmL20yF2iL50xSv4doxijR1Jsih0UkrzwGbHl44SguPVAnginfHGTgYfkn7kYawg0TAtNJnMqEAi07KY1cjLtn+Hz4V99xuZ+bgRS/XmH4isLoe0VBdpGoqMLZNp2oPa+7Wgz1Dh2ZHGDmBorwCFfQgU9Fo88DcJmbkEPBdGifRr6sujXj+/p71NMDNs4J7W22UxjyUzlWc7HHpCi5ELkpMUpJryalEjyyooLTMHYonBLUjEXgFQID5v5IFKSCgYzr7Whvr6hwabBwS8zpzB4a1TxFLQjmQB82CdsJgH6rICTi0KG2SgofAMufLiSNLQwzgIiFQdhY+DEoXgk5kDLyZO708iK9vRpH8fHW1VEw6MZNmg0IoQgZvSimPez4CVcmAxsJIUGcnkcCRlYGO9HIk6Fkz2dnNx3zNSdkwoEg0GICHZNY1g4cIEMh9lRNyGQXTh4s5hVoLQBXEkh06VjeRjUk/GqhoUTxQ2cCsyNMe9uSWVSwUwmqA10DbyorBwc6gvZCYfDxWDREsqNzUpKZjLQTgQXVKCTKhD/lYVBRhKltnrFhYLLuSsCT6FBHqiBVcQUWQu5wIsejKWBIMA6SWv9/eFsP7HB41EqhMNht1hwWMTrEuAiifl4MJdp3GUyX07QmYVYJknYjIIOhf5lMUkKSA0Taaxi7WXFEibFzVblixWl0+lAipY7RB496sfQv9LD4TIONrKZS8E9CJEWuLjRozsRLoSJC4E/M6aj6odNlYYpD/IoRiVLWKuc2z2Bo7zIiE7zkI9MkO1a4fAjzsrpAo8yEpCNw8gEJThN95bCBEAHHaT5SDOAfOFgQA8v+HYPbATNaDMR6xDI8tZ13esm0MhoZkKSElgM6xnW09OjZbPRaF02Gw6vrJkzB8d0hUfxlxP3KSMNYLd7vN5SMFFBfaICaWYyhvbynFJBf6kbja+AEk44gF0AIbajCuC1oCeYQjpgot0WNG8ZL6iBDiAlQyvSIVx4wgMi02tqakolU4kJE8ScvCAGIYVNWEBjYvFUXjPoJWW/3rl1uZ/wpJcBx9+UqEyBuc9BJtPz6ZMWRjKiWSZiAJzgxc0Knew04AJEmApy4+XoBM5CDEIS+vkzK/aLaanbretFRagaJu726haHCxIKMtmAB40c2nXIiPBd+PjxB0xev9eiddFo8+3b0eyW8RTt+P+CkOGkEB44/VGwAwuezEUGCaTWFAI//1JYsJ5ji46lRuh2B1lYrevWrbNardu3z98g2M4QalLJFeoa6Op6s2jRrxdaIt68rDYKtsyR/N+FdGSOeLaYiMejy00PsKr2KtxscEubUqbhoB3dRS7kbT/vKCsjDSBUhMdm62YrQwmR0tbOxmudnZsaBzq0RCxWX18fT8R/cot/qxxVqIvcSJUc36/LCKhQTvAAGOUEMryKqIzKZootkFbceQd5bIeHD8CE4uYewAe4nlJ623D8envD8Y76OxppxOKxWLwZKVEYiRibQERpwAOxzeSJhwly9DeUI8ArkO5F3AKIA3yMexw7hrApaOnhy4eUktU3GxraTzfc67inLd8TiXRE9ixfvjzxc0shKwmcBJgYgBtCoZD/ht9/42/8IV9o8x/4FPfhNr+Ppv6Qn7GVjfgDODeSyX1EEtB7W4kkLuaT/HiuoqLi5tn29vbjq7UIJPZcjdyJ3KlfUr88HsMRSyBBCQw4Yr3v4vHEy8S7d4lEM1G3LFpbGw2Hw4/DdbW1dace82nv2qH7h4infTT2YQS3zt0abGwc6O3qfdF77961WPzlpbO3nnR3P7l1KXK2qqKpq7Gysrq6unNTZ3VTZfVgeXn53fLy+0+6W1sfXHxwHxw/09lx/UTF4bNV69ev37lz796Nra3drd1gW+ve/ef2rt+/s+pEVdWJE5d/U1s+PWpCURS3xrTph2P1IuFtpi8ZIGEBCRsIJoWFAikVTKZsykhU/nTRwYmuiI6y0FlUnUmqMZmu6maS6WL6HXqpi1m0TdNlD7wnwku8P865SIUQbJINm63aOj/lGV5neJ5jdIR0cIk+g/IvaKA6PJyjfr8PJBevS21hvNkCw+v3sG23wPIwitKb79++fV8fkW5KmPTdus6ygTMazUfzla6PNkni7t0lyaJo2J3NHGc2H63G3Varzr59ewpqrfeXP7UHkEUcb8LC9D3RsgRsqEAolUNS4cO6tlXRI6En+KZbcUVLtEXBiNubzXgcx+PVeLxqN9uMRtEUTyGmT1MchyiEEN+nKETRZ1P6TFHAm7Mz+oKmFQp8AW/Apbu7g8O26if3zke40879R+fktH4SOFBeV45leT6X5ys5WebY3e8zUDBz5uO4vOfLvNtiT04DWMrWl+m769vbdH2TpmQ8DofEt2wLh8S1JOny9hbcAgzpgyqp16mRY0EVBLWSm5jg3PA8w1gu4qyJmPZUb7fbSAd/KB5coWgaSHRAQDTV5JtNGLyCKAZRCjUAgm3v9Wulp9BK73354vZpFC3rp8H918evpR4Oh8PD193IkR1WZicQoygebrIsiRMzYydFYZKCuELgBCUv24L2ZcuMgZZrS5oUJCwEVa2ZoaGq0u3th8vLDpA0SldqkC9DsGqqqFZsT1QFMMcQRCG1LXOYZYCxgnLb7el4BUYw6FynIGV0aQdsCIFRmkKjJq0oAwVOaTTMDM3DNZ6n3m/ffP50PmLXEVuPWDlwZo+Ph8Pj7vFhdw8Rm81lOY834ySKyKSbJKaoWq4QyfJp4ABMa7E4rUPQ6pDHk/oirbP1bmgKlkVCAUAuS3U6ktRo1GoNqaFaqgpIDbXy0vRUUXSx5b1a+IJnip7rmSTJhuSiTzOMzqDmOWqWBSpwADbwCEHkOCCiLprNFWpSFA3OQM/0NI2CLFKMDojv7+7OzmXipjfrG0AKRrvdDmBG8xm0SwsnxMDDpIiHMXYh29eCiYNZ8DYI2FNZlo/mBLPZ0abuq9YiH85EuyZBrICjZGk0JBhgSwOYpFrluYkFbEOXwPAMURCwT0xBFG3bx6QIdcToFM9BuDgewsYpUD/FMQzU20do2m5OpwzD8ABKc0c6fjpF0+kUngw0ePNp111DQ6T7dLFIongyH0GrjCYy21q6KcZJNyQ4i33RhN/E8BidyPKmKIavwBMwM3BYttvtDufjYSE7UddIhWtL6lx1YIf6O6XKA6n2vPKCYH/peTZEzHdFEWhE1xYxMT3Dz0XPDzfjVaFr2kDTNF7jBtqA4wY90EAZcFqvnKB0itOAkZs2EQcG8UyZQMgm4nu97fbusMlT63rv7q19mkcRG2VZvohaZX8vCMZ5HOK4yIwPqmuGyRAXGTZczyA+HobYEIwveDie7+BVhAW2FBtirfGTpHN1dXUcjdqLSvXFc0LM8EvuGZ6fY8M0bNcTPeLlguH7Zu77X0Lf98N4tVnpXPlsBhpuADicph2JQEAJExxDvEprNBCH2owOdlGwCl5MR5lpw58A7O46zbPlMoogRGzMsoslTglJ4gxbNjZtl5i2akNkarboC7UyOpZNwDujPgnY+iKKkyjx7VoJclTj+YtqpVp9Vn32v6taLUH+f44jyFG/uQj7L+dg+/u5Pyz511XVp8+n+enL03UQgPxgjwxyKASBGDrp/Q/9/b7oy0QMCzYuaAiWdqaAVHiUIHF+lPN7B5iIAQ9rBpkkEYdIIXJoDhYU4FF/DhO1O3eb+iOgIpnD4i+gDvAo1+zpnPtN5VVNsUlSegeHqiqyi7AEaKuKasgrd+bCrNgdIHY2iM+jEiiqCW6uJRM6xsVjwvPeT6lOBonyUZui5fqDNvcyYQmZSd1ai1/P8//NizY2Nn7twSEBAAAAgKD/r71hAAAAAOAvLhYmRt/r5CIAAAAASUVORK5CYII=", + "description": "Displays historical temperature values as a simplified chart with background. Optionally may display the corresponding latest temperature value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'temperature', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Temperature\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"thermostat\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"°C\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/temperature_card.json b/application/src/main/data/json/system/widget_types/temperature_card.json new file mode 100644 index 0000000000..8986d46d23 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/temperature_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "temperature_card", + "name": "Temperature card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest temperature telemetry data in a box layout.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Temperature card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/temperature_card_with_background.json b/application/src/main/data/json/system/widget_types/temperature_card_with_background.json new file mode 100644 index 0000000000..e6743fbe8a --- /dev/null +++ b/application/src/main/data/json/system/widget_types/temperature_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "temperature_card_with_background", + "name": "Temperature card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest temperature telemetry data in a box layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'temperature', label: 'Temperature', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Temperature card with background\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/temperature_chart_card.json b/application/src/main/data/json/system/widget_types/temperature_chart_card.json new file mode 100644 index 0000000000..3f23b0e277 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/temperature_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "temperature_chart_card", + "name": "Temperature chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a temperature data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#234CC7\"},{\"from\":-20,\"to\":0,\"color\":\"#305AD7\"},{\"from\":0,\"to\":10,\"color\":\"#7191EF\"},{\"from\":10,\"to\":20,\"color\":\"#FFA600\"},{\"from\":20,\"to\":30,\"color\":\"#F36900\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Temperature\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"device_thermostat\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json new file mode 100644 index 0000000000..9d5ebe5911 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "temperature_chart_card_with_background", + "name": "Temperature chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a temperature data as a combination of the latest and aggregated values with background. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":-20,\"color\":\"#224AC2\"},{\"from\":-20,\"to\":0,\"color\":\"#2B54CE\"},{\"from\":0,\"to\":10,\"color\":\"#6083EC\"},{\"from\":10,\"to\":20,\"color\":\"#F89E0D\"},{\"from\":20,\"to\":30,\"color\":\"#F77410\"},{\"from\":30,\"to\":40,\"color\":\"#F04022\"},{\"from\":40,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"°C\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Temperature\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"device_thermostat\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "temperature", + "weather", + "environment" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/value_and_chart_card.json b/application/src/main/data/json/system/widget_types/value_and_chart_card.json index aa8e6b31ee..10cfba9105 100644 --- a/application/src/main/data/json/system/widget_types/value_and_chart_card.json +++ b/application/src/main/data/json/system/widget_types/value_and_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'watermeter', label: 'Watermeter', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'watermeter', label: 'Watermeter', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³');\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 0bb9d67c07..19d7780a79 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -534,6 +534,7 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("count_widgets"); this.deleteSystemWidgetBundle("weather_widgets"); this.deleteSystemWidgetBundle("status_indicators"); + this.deleteSystemWidgetBundle("outdoor_environment"); installScripts.loadSystemWidgets(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts index ad88ee79a0..b8794b37fc 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts @@ -117,27 +117,81 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo } protected defaultLatestDataKeys(configData: WidgetConfigComponentData): DataKey[] { - return this.createDefaultAggregatedValueLatestDataKeys('watermeter', 'm³'); + return this.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³'); } - createDefaultAggregatedValueLatestDataKeys(keyName: string, units): DataKey[] { + createDefaultAggregatedValueLatestDataKeys(configData: WidgetConfigComponentData, keyName: string, units): DataKey[] { + let centerKeySettings: AggregatedValueCardKeySettings = { + position: AggregatedValueCardKeyPosition.center, + font: { + family: 'Roboto', + size: 52, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.87)'), + showArrow: false + }; + let rightTopKeySettings: AggregatedValueCardKeySettings = { + position: AggregatedValueCardKeyPosition.rightTop, + font: { + family: 'Roboto', + size: 14, + sizeUnit: 'px', + style: 'normal', + weight: '500', + lineHeight: '1' + }, + color: { + color: 'rgba(0, 0, 0, 0.87)', + type: ColorType.range, + rangeList: [ + {to: 0, color: '#198038'}, + {from: 0, to: 0, color: 'rgba(0, 0, 0, 0.87)'}, + {from: 0, color: '#D12730'} + ], + colorFunction: '' + }, + showArrow: true + }; + let rightBottomKeySettings: AggregatedValueCardKeySettings = { + position: AggregatedValueCardKeyPosition.rightBottom, + font: { + family: 'Roboto', + size: 11, + sizeUnit: 'px', + style: 'normal', + weight: '400', + lineHeight: '1' + }, + color: constantColor('rgba(0, 0, 0, 0.38)'), + showArrow: false + }; + const datasources: Datasource[] = configData.config.datasources; + if (datasources?.length) { + const latestDataKeys = datasources[0].latestDataKeys; + if (latestDataKeys) { + const center = latestDataKeys.find(dataKey => dataKey.settings?.position === AggregatedValueCardKeyPosition.center); + if (center) { + centerKeySettings = {...centerKeySettings, ...center.settings}; + } + const rightTop = latestDataKeys.find(dataKey => dataKey.settings?.position === AggregatedValueCardKeyPosition.rightTop); + if (rightTop) { + rightTopKeySettings = {...rightTopKeySettings, ...rightTop.settings}; + } + const rightBottom = latestDataKeys.find(dataKey => dataKey.settings?.position === AggregatedValueCardKeyPosition.rightBottom); + if (rightBottom) { + rightBottomKeySettings = {...rightBottomKeySettings, ...rightBottom.settings}; + } + } + } return [ { name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals: 0, aggregationType: AggregationType.NONE, - settings: { - position: AggregatedValueCardKeyPosition.center, - font: { - family: 'Roboto', - size: 52, - sizeUnit: 'px', - style: 'normal', - weight: '500', - lineHeight: '1' - }, - color: constantColor('rgba(0, 0, 0, 0.87)'), - showArrow: false - } as AggregatedValueCardKeySettings + settings: centerKeySettings }, { name: keyName, label: 'Delta percent', type: DataKeyType.timeseries, units: '%', decimals: 0, @@ -145,28 +199,7 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo comparisonEnabled: true, timeForComparison: 'previousInterval', comparisonResultType: ComparisonResultType.DELTA_PERCENT, - settings: { - position: AggregatedValueCardKeyPosition.rightTop, - font: { - family: 'Roboto', - size: 14, - sizeUnit: 'px', - style: 'normal', - weight: '500', - lineHeight: '1' - }, - color: { - color: 'rgba(0, 0, 0, 0.87)', - type: ColorType.range, - rangeList: [ - {to: 0, color: '#198038'}, - {from: 0, to: 0, color: 'rgba(0, 0, 0, 0.87)'}, - {from: 0, color: '#D12730'} - ], - colorFunction: '' - }, - showArrow: true - } as AggregatedValueCardKeySettings + settings: rightTopKeySettings }, { name: keyName, label: 'Delta absolute', type: DataKeyType.timeseries, units, decimals: 1, @@ -174,19 +207,7 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo comparisonEnabled: true, timeForComparison: 'previousInterval', comparisonResultType: ComparisonResultType.DELTA_ABSOLUTE, - settings: { - position: AggregatedValueCardKeyPosition.rightBottom, - font: { - family: 'Roboto', - size: 11, - sizeUnit: 'px', - style: 'normal', - weight: '400', - lineHeight: '1' - }, - color: constantColor('rgba(0, 0, 0, 0.38)'), - showArrow: false - } as AggregatedValueCardKeySettings + settings: rightBottomKeySettings } ]; } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts index d3ba1d1daa..ea9a6bbcb2 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts @@ -607,7 +607,9 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe this.gotError = false; this.iframeWidgetEditModeInited = false; const config: WidgetConfig = JSON.parse(this.widget.defaultConfig); - config.title = this.widget.widgetName; + if (!config.title) { + config.title = this.widget.widgetName; + } this.widget.defaultConfig = JSON.stringify(config); this.iframe.attr('data-widget', JSON.stringify(this.widget)); // @ts-ignore From 2a4b34893139bf40876fd3ef5ff0d4722732f06a Mon Sep 17 00:00:00 2001 From: rusikv Date: Wed, 18 Oct 2023 18:44:25 +0300 Subject: [PATCH 204/267] UI: added decibel-milliwatts unit to dictionary --- ui-ngx/src/assets/locale/locale.constant-en_US.json | 1 + ui-ngx/src/assets/metadata/units.json | 5 +++++ 2 files changed, 6 insertions(+) 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 b4c0f07c85..0326633be4 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -4388,6 +4388,7 @@ "volt": "Volt", "kilovolts": "Kilovolts", "dbmV": "dBmV", + "dbm": "dBm", "volt-meter": "Volt-Meter", "kilovolt-meter": "Kilovolt-Meter", "megavolt-meter": "Megavolt-Meter", diff --git a/ui-ngx/src/assets/metadata/units.json b/ui-ngx/src/assets/metadata/units.json index 988c3f34ce..5d680c6e2c 100644 --- a/ui-ngx/src/assets/metadata/units.json +++ b/ui-ngx/src/assets/metadata/units.json @@ -938,6 +938,11 @@ "symbol": "dBmV", "tags": ["decibels millivolt","voltage level","signal","dBmV"] }, +{ + "name": "unit.dbm", + "symbol": "dBm", + "tags": ["decibel milliwatts","output power","signal","dBm"] +}, { "name": "unit.volt-meter", "symbol": "V·m", From 9cb16b1c14812f67891bb06d825648468d796b63 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Wed, 18 Oct 2023 18:47:10 +0300 Subject: [PATCH 205/267] UI: Update temperature widgets preview images --- .../json/system/widget_types/simple_temperature_chart_card.json | 2 +- .../data/json/system/widget_types/temperature_chart_card.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json index f89e7ec47b..6645b0e427 100644 --- a/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json +++ b/application/src/main/data/json/system/widget_types/simple_temperature_chart_card.json @@ -2,7 +2,7 @@ "fqn": "simple_temperature_chart_card", "name": "Simple temperature chart card", "deprecated": false, - "image": "data:image/png;base64,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", + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAe1BMVEUAAADg4ODf39/g4ODg4OD////g4OAjTMchISHHx8c8PDzj4+Px8fGQkJCsrKx0dHRaedXk6fhYWFgvLy8+Ys7I0vGCgoKsvOry9PuRpeN1j9yenp5KSkrV1dWfsedohNkwV8tmZma6urqDmt+RpuNMbtLW3fW6x+65ubn1i4vJAAAABXRSTlMA7yC/r1EOHTEAAATQSURBVHja7M9JAcAgDAAwytEX/vUOGdAlDtIAAAAAAAB+p4/I181+HrHX83b0Ngs8zmS0XCVElUiKXEbkNh979q7qOAxFYbhasPZFEkjgxnJhV3n/JxwfJwzKSQwDw3iUg34wEtuNvsJg0ID01oD01oD01oD01oD01oD01inEpohP6hSSkzYSD0cbuu0UorGGBpJSZUoRf5yo4crOIbcc0BZ4iOJmgJhE27eAy7EA+wCwRQQeo8Fn3twFMIHLsgESBW2XQbZ3ECtV1UHdl5qZIdTMBKwlc0YqXE3zSlkq6xIJBEVkqQgl64SmyyCpvoHkDJQABmzcMBPCBYG+0RAUSQ1LAGqC0PAbYjDGY9R0DcQLmV4hqjmXhONUgkjIcUgJJWclUgYwr1q+QQBhzpWCpmsgiXvyCllFxL5BFkqg7B2QSPH8BhJFxNF0DYRfpRfIpIb5GRKR1IUzZD4goZhperxffL1DvEzwgLZrIIV70wvEV1KfIcoyA4Esd4gpS81wZfSv7R2Cm5L/42OfSRbDa/48FJr5fe54ZP5Y7k8zbrsIgpgmw2ktBF10QP4iC53cSvz8v99Pa0B6a0B6a0B6a0B6a0B6a0D+cb7Ns/jHQ36xa25LjoJAAH3qAgFFvBITo1k35v//cMHWwR3NxBqtmVjleZjh9tAnDaSpCpfUEmdi3yIli31PCE9SxvcswtkQfxkzsWMRGXP3kva3EkmLMKyu6qPbmG6u3HxehTn06GuFs6vgNHOdKBabiKiQdNR9sH+xm7SA4ECD7Wvdz17XJYRyQDAlW4joxDhUlflL0iHs0HZr3YuSRKs7aYfJ+t6ZrzJhEhCXknUiGFuiAEyopOq9bGoqQk7QkdqY824wtwLGT5+c51LEWUYZx3ZAPRjh0fMGIkmfidQIAcDD5AMMrQkVOlorWHSLkg+7EFvL4YyyiOImEozBf0RsvYgmhIBFYaMxEQ6Cagg6ScgdXYexnJiR53g3xm4BIH3snrHJqPR4wGj5aTn9sz4jSmFsKYYWdjsLG4/etajrRtuTbrOFqKIovjrLsbyx8c3kU97/N1inzynhK0UcBZ7fEHcaGk2XNLCADHeQ70w4lYAILyhhQhkzvokIHhH1QmTZwcCoUUgAwhh/WbHI0mpKRulF8uUiqkN/dPGy2kTkTPs4BM2GkWBRDWkkYun7t5hKvlSEdIQjjwY2ErlE0JPhverFtyWJDDLpe9j0mVH5hoi+E1LAS5FikUjpPn4R0cj3I1fgLgRVskUiaUeLncpdptXk1nI0VhfRSqmnR30UdnChlPkCHMtVzq9FpgEmenx5We6YmjG5WefuhhrmYRFsjxN5XaQgV0KK4YsS5Ry6Rjn0rWAWz+2sHxZxHr1ArVAonE2dGsqA/NlLQ8AKVhWNpDghDzwbySO1o/lspZyc8rypJ5pzNfnPioTEUeBNjJxggpskoZ73GD9cf1cEVPHFy0mdkk5jflZk9PIDv0VZTtsqeIpKWw2zeIxmAhy/L/ItRDYpa3cpMpeOPYr4c+nYo8htLh17FJnhEDlE9sIh8m4cIu/GIfJuHCLvxiHyr507NwIghIEgKJ6TdfnHSxA4ArozWH9rqjGkmoz2XSFjFDm37/nnPRGk6DNP10YPAAAAAACA1yz9maqJM0bCeAAAAABJRU5ErkJggg==", "description": "Displays historical temperature values as a simplified chart. Optionally may display the corresponding latest temperature value.", "descriptor": { "type": "timeseries", diff --git a/application/src/main/data/json/system/widget_types/temperature_chart_card.json b/application/src/main/data/json/system/widget_types/temperature_chart_card.json index 3f23b0e277..4aecc59cdf 100644 --- a/application/src/main/data/json/system/widget_types/temperature_chart_card.json +++ b/application/src/main/data/json/system/widget_types/temperature_chart_card.json @@ -2,7 +2,7 @@ "fqn": "temperature_chart_card", "name": "Temperature chart card", "deprecated": false, - "image": "data:image/png;base64,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", + "image": "data:image/png;base64,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", "description": "Displays a temperature data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", "descriptor": { "type": "timeseries", From 92a2a90a0bc0896363548220cd0e94792a92e15f Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Tue, 17 Oct 2023 12:03:24 +0200 Subject: [PATCH 206/267] ComponentLifecycleMsgProto implemented as replacement of raw byte encoding --- .../queue/DefaultTbClusterService.java | 6 +- .../queue/DefaultTbCoreConsumerService.java | 4 + .../DefaultTbRuleEngineConsumerService.java | 6 +- .../server/service/queue/ProtoUtils.java | 47 ++++++++++ .../service/queue/TbCoreConsumerStats.java | 2 + .../processing/AbstractConsumerService.java | 86 ++++++++++--------- .../server/service/queue/ProtoUtilsTest.java | 71 +++++++++++++++ common/cluster-api/src/main/proto/queue.proto | 58 ++++++++++++- .../server/common/data/EntityType.java | 1 + .../common/data/id/EntityIdFactory.java | 4 + .../data/plugin/ComponentLifecycleEvent.java | 1 + .../msg/plugin/ComponentLifecycleMsg.java | 14 +-- .../common/msg/plugin/RuleNodeUpdatedMsg.java | 6 +- 13 files changed, 245 insertions(+), 61 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java create mode 100644 application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java 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 53ef38d96a..937ee12fab 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 @@ -395,7 +395,7 @@ public class DefaultTbClusterService implements TbClusterService { } private void broadcast(ComponentLifecycleMsg msg) { - byte[] msgBytes = encodingService.encode(msg); + TransportProtos.ComponentLifecycleMsgProto componentLifecycleMsgProto = ProtoUtils.toProto(msg); TbQueueProducer> toRuleEngineProducer = producerProvider.getRuleEngineNotificationsMsgProducer(); Set tbRuleEngineServices = partitionService.getAllServiceIds(ServiceType.TB_RULE_ENGINE); EntityType entityType = msg.getEntityId().getEntityType(); @@ -413,7 +413,7 @@ public class DefaultTbClusterService implements TbClusterService { Set tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); for (String serviceId : tbCoreServices) { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_CORE, serviceId); - ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setComponentLifecycleMsg(ByteString.copyFrom(msgBytes)).build(); + ToCoreNotificationMsg toCoreMsg = ToCoreNotificationMsg.newBuilder().setComponentLifecycle(componentLifecycleMsgProto).build(); toCoreNfProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEntityId().getId(), toCoreMsg), null); toCoreNfs.incrementAndGet(); } @@ -422,7 +422,7 @@ public class DefaultTbClusterService implements TbClusterService { } for (String serviceId : tbRuleEngineServices) { TopicPartitionInfo tpi = notificationsTopicService.getNotificationsTopic(ServiceType.TB_RULE_ENGINE, serviceId); - ToRuleEngineNotificationMsg toRuleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setComponentLifecycleMsg(ByteString.copyFrom(msgBytes)).build(); + ToRuleEngineNotificationMsg toRuleEngineMsg = ToRuleEngineNotificationMsg.newBuilder().setComponentLifecycle(componentLifecycleMsgProto).build(); toRuleEngineProducer.send(tpi, new TbProtoQueueMsg<>(msg.getEntityId().getId(), toRuleEngineMsg), null); toRuleEngineNfs.incrementAndGet(); } 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 fd5a252cc5..bae1ea35a6 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 @@ -346,7 +346,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService msg, TbCallback callback) throws Exception { ToRuleEngineNotificationMsg nfMsg = msg.getValue(); - if (nfMsg.getComponentLifecycleMsg() != null && !nfMsg.getComponentLifecycleMsg().isEmpty()) { + if (nfMsg.hasComponentLifecycle()) { + handleComponentLifecycleMsg(id, ProtoUtils.fromProto(nfMsg.getComponentLifecycle())); + callback.onSuccess(); + } else if (nfMsg.getComponentLifecycleMsg() != null && !nfMsg.getComponentLifecycleMsg().isEmpty()) { + //will be removed in 3.6.1 in favour of hasComponentLifecycle() handleComponentLifecycleMsg(id, nfMsg.getComponentLifecycleMsg()); callback.onSuccess(); } else if (nfMsg.hasFromDeviceRpcResponse()) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java b/application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java new file mode 100644 index 0000000000..3406265747 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ProtoUtils.java @@ -0,0 +1,47 @@ +/** + * Copyright © 2016-2023 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.queue; + +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; +import org.thingsboard.server.gen.transport.TransportProtos; + +import java.util.UUID; + +public class ProtoUtils { + + public static TransportProtos.ComponentLifecycleMsgProto toProto(ComponentLifecycleMsg msg) { + return TransportProtos.ComponentLifecycleMsgProto.newBuilder() + .setTenantIdMSB(msg.getTenantId().getId().getMostSignificantBits()) + .setTenantIdLSB(msg.getTenantId().getId().getLeastSignificantBits()) + .setEntityType(TransportProtos.EntityType.forNumber(msg.getEntityId().getEntityType().ordinal())) + .setEntityIdMSB(msg.getEntityId().getId().getMostSignificantBits()) + .setEntityIdLSB(msg.getEntityId().getId().getLeastSignificantBits()) + .setEvent(TransportProtos.ComponentLifecycleEvent.forNumber(msg.getEvent().ordinal())) + .build(); + } + + public static ComponentLifecycleMsg fromProto(TransportProtos.ComponentLifecycleMsgProto proto) { + return new ComponentLifecycleMsg( + TenantId.fromUUID(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB())), + EntityIdFactory.getByTypeAndUuid(proto.getEntityTypeValue(), new UUID(proto.getEntityIdMSB(), proto.getEntityIdLSB())), + ComponentLifecycleEvent.values()[proto.getEventValue()] + ); + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java b/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java index 4d195a0dec..9107159615 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbCoreConsumerStats.java @@ -168,6 +168,8 @@ public class TbCoreConsumerStats { toCoreNfSubscriptionServiceCounter.increment(); } else if (msg.hasFromDeviceRpcResponse()) { toCoreNfDeviceRpcResponseCounter.increment(); + } else if (msg.hasComponentLifecycle()) { + toCoreNfComponentLifecycleCounter.increment(); } else if (!msg.getComponentLifecycleMsg().isEmpty()) { toCoreNfComponentLifecycleCounter.increment(); } else if (!msg.getEdgeEventUpdateMsg().isEmpty()) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index b59086a350..591bc058c1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -166,55 +166,57 @@ public abstract class AbstractConsumerService actorMsgOpt = encodingService.decode(nfMsg.toByteArray()); - if (actorMsgOpt.isPresent()) { - TbActorMsg actorMsg = actorMsgOpt.get(); - if (actorMsg instanceof ComponentLifecycleMsg) { - ComponentLifecycleMsg componentLifecycleMsg = (ComponentLifecycleMsg) actorMsg; - log.debug("[{}][{}][{}] Received Lifecycle event: {}", componentLifecycleMsg.getTenantId(), componentLifecycleMsg.getEntityId().getEntityType(), - componentLifecycleMsg.getEntityId(), componentLifecycleMsg.getEvent()); - if (EntityType.TENANT_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - TenantProfileId tenantProfileId = new TenantProfileId(componentLifecycleMsg.getEntityId().getId()); - tenantProfileCache.evict(tenantProfileId); + actorMsgOpt.ifPresent(tbActorMsg -> handleComponentLifecycleMsg(id, tbActorMsg)); + } + + protected void handleComponentLifecycleMsg(UUID id, TbActorMsg actorMsg) { + if (actorMsg instanceof ComponentLifecycleMsg) { + ComponentLifecycleMsg componentLifecycleMsg = (ComponentLifecycleMsg) actorMsg; + log.debug("[{}][{}][{}] Received Lifecycle event: {}", componentLifecycleMsg.getTenantId(), componentLifecycleMsg.getEntityId().getEntityType(), + componentLifecycleMsg.getEntityId(), componentLifecycleMsg.getEvent()); + if (EntityType.TENANT_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + TenantProfileId tenantProfileId = new TenantProfileId(componentLifecycleMsg.getEntityId().getId()); + tenantProfileCache.evict(tenantProfileId); + if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) { + apiUsageStateService.onTenantProfileUpdate(tenantProfileId); + } + } else if (EntityType.TENANT.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + if (TenantId.SYS_TENANT_ID.equals(componentLifecycleMsg.getTenantId())) { + jwtSettingsService.ifPresent(JwtSettingsService::reloadJwtSettings); + return; + } else { + tenantProfileCache.evict(componentLifecycleMsg.getTenantId()); + partitionService.removeTenant(componentLifecycleMsg.getTenantId()); if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) { - apiUsageStateService.onTenantProfileUpdate(tenantProfileId); - } - } else if (EntityType.TENANT.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - if (TenantId.SYS_TENANT_ID.equals(componentLifecycleMsg.getTenantId())) { - jwtSettingsService.ifPresent(JwtSettingsService::reloadJwtSettings); - return; - } else { - tenantProfileCache.evict(componentLifecycleMsg.getTenantId()); - partitionService.removeTenant(componentLifecycleMsg.getTenantId()); - if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.UPDATED)) { - apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId()); - } else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) { - apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId()); - } - } - } else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId())); - } else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceId(componentLifecycleMsg.getEntityId().getId())); - } else if (EntityType.ASSET_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - assetProfileCache.evict(componentLifecycleMsg.getTenantId(), new AssetProfileId(componentLifecycleMsg.getEntityId().getId())); - } else if (EntityType.ASSET.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - assetProfileCache.evict(componentLifecycleMsg.getTenantId(), new AssetId(componentLifecycleMsg.getEntityId().getId())); - } else if (EntityType.ENTITY_VIEW.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - actorContext.getTbEntityViewService().onComponentLifecycleMsg(componentLifecycleMsg); - } else if (EntityType.API_USAGE_STATE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - apiUsageStateService.onApiUsageStateUpdate(componentLifecycleMsg.getTenantId()); - } else if (EntityType.CUSTOMER.equals(componentLifecycleMsg.getEntityId().getEntityType())) { - if (componentLifecycleMsg.getEvent() == ComponentLifecycleEvent.DELETED) { - apiUsageStateService.onCustomerDelete((CustomerId) componentLifecycleMsg.getEntityId()); + apiUsageStateService.onTenantUpdate(componentLifecycleMsg.getTenantId()); + } else if (componentLifecycleMsg.getEvent().equals(ComponentLifecycleEvent.DELETED)) { + apiUsageStateService.onTenantDelete((TenantId) componentLifecycleMsg.getEntityId()); } } - eventPublisher.publishEvent(componentLifecycleMsg); + } else if (EntityType.DEVICE_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceProfileId(componentLifecycleMsg.getEntityId().getId())); + } else if (EntityType.DEVICE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + deviceProfileCache.evict(componentLifecycleMsg.getTenantId(), new DeviceId(componentLifecycleMsg.getEntityId().getId())); + } else if (EntityType.ASSET_PROFILE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + assetProfileCache.evict(componentLifecycleMsg.getTenantId(), new AssetProfileId(componentLifecycleMsg.getEntityId().getId())); + } else if (EntityType.ASSET.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + assetProfileCache.evict(componentLifecycleMsg.getTenantId(), new AssetId(componentLifecycleMsg.getEntityId().getId())); + } else if (EntityType.ENTITY_VIEW.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + actorContext.getTbEntityViewService().onComponentLifecycleMsg(componentLifecycleMsg); + } else if (EntityType.API_USAGE_STATE.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + apiUsageStateService.onApiUsageStateUpdate(componentLifecycleMsg.getTenantId()); + } else if (EntityType.CUSTOMER.equals(componentLifecycleMsg.getEntityId().getEntityType())) { + if (componentLifecycleMsg.getEvent() == ComponentLifecycleEvent.DELETED) { + apiUsageStateService.onCustomerDelete((CustomerId) componentLifecycleMsg.getEntityId()); + } } - log.trace("[{}] Forwarding message to App Actor {}", id, actorMsg); - actorContext.tellWithHighPriority(actorMsg); + eventPublisher.publishEvent(componentLifecycleMsg); } + log.trace("[{}] Forwarding component lifecycle message to App Actor {}", id, actorMsg); + actorContext.tellWithHighPriority(actorMsg); } protected abstract void handleNotification(UUID id, TbProtoQueueMsg msg, TbCallback callback) throws Exception; diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java new file mode 100644 index 0000000000..c63055a6f1 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/queue/ProtoUtilsTest.java @@ -0,0 +1,71 @@ +/** + * Copyright © 2016-2023 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.queue; + +import org.junit.jupiter.api.Test; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.RuleChainId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; +import org.thingsboard.server.gen.transport.TransportProtos; +import java.util.UUID; + +import static org.assertj.core.api.Assertions.assertThat; + +class ProtoUtilsTest { + + TenantId tenantId = TenantId.fromUUID(UUID.fromString("35e10f77-16e7-424d-ae46-ee780f87ac4f")); + EntityId entityId = new RuleChainId(UUID.fromString("c640b635-4f0f-41e6-b10b-25a86003094e")); + @Test + void toProtoComponentLifecycleMsg() { + ComponentLifecycleMsg msg = new ComponentLifecycleMsg(tenantId, entityId, ComponentLifecycleEvent.UPDATED); + + TransportProtos.ComponentLifecycleMsgProto proto = ProtoUtils.toProto(msg); + + assertThat(proto).as("to proto").isEqualTo(TransportProtos.ComponentLifecycleMsgProto.newBuilder() + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .setEntityType(TransportProtos.EntityType.forNumber(entityId.getEntityType().ordinal())) + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) + .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) + .setEvent(TransportProtos.ComponentLifecycleEvent.forNumber(ComponentLifecycleEvent.UPDATED.ordinal())) + .build() + ); + + assertThat(ProtoUtils.fromProto(proto)).as("from proto").isEqualTo(msg); + } + + @Test + void fromProtoComponentLifecycleMsg() { + TransportProtos.ComponentLifecycleMsgProto proto = TransportProtos.ComponentLifecycleMsgProto.newBuilder() + .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) + .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) + .setEntityType(TransportProtos.EntityType.forNumber(entityId.getEntityType().ordinal())) + .setEntityIdMSB(entityId.getId().getMostSignificantBits()) + .setEntityIdLSB(entityId.getId().getLeastSignificantBits()) + .setEvent(TransportProtos.ComponentLifecycleEvent.forNumber(ComponentLifecycleEvent.STARTED.ordinal())) + .build(); + + ComponentLifecycleMsg msg = ProtoUtils.fromProto(proto); + + assertThat(msg).as("from proto").isEqualTo( + new ComponentLifecycleMsg(tenantId, entityId, ComponentLifecycleEvent.STARTED)); + + assertThat(ProtoUtils.toProto(msg)).as("to proto").isEqualTo(proto); + } + +} \ No newline at end of file diff --git a/common/cluster-api/src/main/proto/queue.proto b/common/cluster-api/src/main/proto/queue.proto index 60dfcae1de..d8439d0cd0 100644 --- a/common/cluster-api/src/main/proto/queue.proto +++ b/common/cluster-api/src/main/proto/queue.proto @@ -20,6 +20,38 @@ package transport; option java_package = "org.thingsboard.server.gen.transport"; option java_outer_classname = "TransportProtos"; +/** + * Common data structures + */ +enum EntityType { + TENANT = 0; + CUSTOMER = 1; + USER = 2; + DASHBOARD = 3; + ASSET = 4; + DEVICE = 5; + ALARM = 6; + RULE_CHAIN = 7; + RULE_NODE = 8; + ENTITY_VIEW = 9; + WIDGETS_BUNDLE = 10; + WIDGET_TYPE = 11; + TENANT_PROFILE = 12; + DEVICE_PROFILE = 13; + ASSET_PROFILE = 14; + API_USAGE_STATE = 15; + TB_RESOURCE = 16; + OTA_PACKAGE = 17; + EDGE = 18; + RPC = 19; + QUEUE = 20; + NOTIFICATION_TARGET = 21; + NOTIFICATION_TEMPLATE = 22; + NOTIFICATION_REQUEST = 23; + NOTIFICATION = 24; + NOTIFICATION_RULE = 25; +} + /** * Service Discovery Data Structures; */ @@ -731,6 +763,25 @@ message FromDeviceRPCResponseProto { int32 error = 4; } +enum ComponentLifecycleEvent { + CREATED = 0; + STARTED = 1; + ACTIVATED = 2; + SUSPENDED = 3; + UPDATED = 4; + STOPPED = 5; + DELETED = 6; +} + +message ComponentLifecycleMsgProto { + int64 tenantIdMSB = 1; + int64 tenantIdLSB = 2; + EntityType entityType = 3; + int64 entityIdMSB = 4; + int64 entityIdLSB = 5; + ComponentLifecycleEvent event = 6; +} + message EdgeNotificationMsgProto { int64 tenantIdMSB = 1; int64 tenantIdLSB = 2; @@ -980,10 +1031,11 @@ message ToCoreMsg { } /* High priority messages with low latency are handled by ThingsBoard Core Service separately */ +/* Please, adjust the TbCoreConsumerStats when modifying the ToCoreNotificationMsg */ message ToCoreNotificationMsg { LocalSubscriptionServiceMsgProto toLocalSubscriptionServiceMsg = 1; FromDeviceRPCResponseProto fromDeviceRpcResponse = 2; - bytes componentLifecycleMsg = 3; + bytes componentLifecycleMsg = 3; //will be removed in 3.6.1 in favour of ComponentLifecycleMsgProto bytes edgeEventUpdateMsg = 4; QueueUpdateMsg queueUpdateMsg = 5; QueueDeleteMsg queueDeleteMsg = 6; @@ -992,6 +1044,7 @@ message ToCoreNotificationMsg { bytes fromEdgeSyncResponseMsg = 9; SubscriptionMgrMsgProto toSubscriptionMgrMsg = 10; NotificationRuleProcessorMsg notificationRuleProcessorMsg = 11; + ComponentLifecycleMsgProto componentLifecycle = 12; } /* Messages that are handled by ThingsBoard RuleEngine Service */ @@ -1004,10 +1057,11 @@ message ToRuleEngineMsg { } message ToRuleEngineNotificationMsg { - bytes componentLifecycleMsg = 1; + bytes componentLifecycleMsg = 1; // will be removed in 3.6.1 in favour of ComponentLifecycleMsgProto FromDeviceRPCResponseProto fromDeviceRpcResponse = 2; QueueUpdateMsg queueUpdateMsg = 3; QueueDeleteMsg queueDeleteMsg = 4; + ComponentLifecycleMsgProto componentLifecycle = 5; } /* Messages that are handled by ThingsBoard Transport Service */ diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 8ca6585718..c4344e8789 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -26,6 +26,7 @@ import java.util.stream.Collectors; * @author Andrew Shvayka */ public enum EntityType { + // In sync with EntityType proto TENANT, CUSTOMER, USER, 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 0cdf3ad1eb..da92eb65d6 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 @@ -29,6 +29,10 @@ public class EntityIdFactory { return getByTypeAndUuid(EntityType.values()[type], UUID.fromString(uuid)); } + public static EntityId getByTypeAndUuid(int type, UUID uuid) { + return getByTypeAndUuid(EntityType.values()[type], uuid); + } + public static EntityId getByTypeAndUuid(String type, String uuid) { return getByTypeAndUuid(EntityType.valueOf(type), UUID.fromString(uuid)); } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java index a7ae9599ea..969baee088 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/plugin/ComponentLifecycleEvent.java @@ -21,5 +21,6 @@ import java.io.Serializable; * @author Andrew Shvayka */ public enum ComponentLifecycleEvent implements Serializable { + // In sync with ComponentLifecycleEvent proto CREATED, STARTED, ACTIVATED, SUSPENDED, UPDATED, STOPPED, DELETED } \ No newline at end of file diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java index b25a8cd3ea..f110a6f209 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/ComponentLifecycleMsg.java @@ -15,8 +15,7 @@ */ package org.thingsboard.server.common.msg.plugin; -import lombok.Getter; -import lombok.ToString; +import lombok.Data; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleChainId; @@ -31,21 +30,12 @@ import java.util.Optional; /** * @author Andrew Shvayka */ -@ToString +@Data public class ComponentLifecycleMsg implements TenantAwareMsg, ToAllNodesMsg { - @Getter private final TenantId tenantId; - @Getter private final EntityId entityId; - @Getter private final ComponentLifecycleEvent event; - public ComponentLifecycleMsg(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent event) { - this.tenantId = tenantId; - this.entityId = entityId; - this.event = event; - } - public Optional getRuleChainId() { return entityId.getEntityType() == EntityType.RULE_CHAIN ? Optional.of((RuleChainId) entityId) : Optional.empty(); } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/RuleNodeUpdatedMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/RuleNodeUpdatedMsg.java index 0a5dfa484f..d912aaa29c 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/RuleNodeUpdatedMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/plugin/RuleNodeUpdatedMsg.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.common.msg.plugin; +import lombok.EqualsAndHashCode; import lombok.ToString; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; @@ -23,8 +24,11 @@ import org.thingsboard.server.common.msg.MsgType; /** * @author Andrew Shvayka + * This class used only to tell local rule-node actor like 'existing.getSelfActor().tellWithHighPriority(new RuleNodeUpdatedMs( ...' + * Never serialized to/from proto, otherwise you need to change proto mappers in ProtoUtils class */ -@ToString +@ToString(callSuper = true) +@EqualsAndHashCode(callSuper = true) public class RuleNodeUpdatedMsg extends ComponentLifecycleMsg { public RuleNodeUpdatedMsg(TenantId tenantId, EntityId entityId) { From 45fd970898930b91a839fcf4fd7f847f00163454 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 18 Sep 2023 12:49:19 +0300 Subject: [PATCH 207/267] Refactoring in progress --- .../DefaultTbRuleEngineConsumerService.java | 201 ++++++++--------- .../queue/TbQueueConsumerLauncher.java | 37 ++++ .../queue/TbQueueConsumerManagerTask.java | 17 ++ .../queue/TbRuleEngineConsumerStats.java | 5 +- .../TbRuleEngineQueueConsumerManager.java | 205 ++++++++++++++++++ .../provider/TbRuleEngineQueueFactory.java | 1 - 6 files changed, 356 insertions(+), 110 deletions(-) create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index c715b7b03c..ae04de456b 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.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, @@ -68,6 +68,7 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrateg import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; import org.thingsboard.server.service.stats.RuleEngineStatisticsService; +import org.threadly.concurrent.wrapper.KeyDistributedExecutor; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; @@ -116,12 +117,12 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< private final QueueService queueService; private final TbQueueProducerProvider producerProvider; private final TbQueueAdmin queueAdmin; - private final ConcurrentMap>> consumers = new ConcurrentHashMap<>(); - private final ConcurrentMap consumerConfigurations = new ConcurrentHashMap<>(); - private final ConcurrentMap consumerStats = new ConcurrentHashMap<>(); - private final ConcurrentMap topicsConsumerPerPartition = new ConcurrentHashMap<>(); - final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); - final ScheduledExecutorService repartitionExecutor = Executors.newScheduledThreadPool(1, ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-repartition")); + + private final ConcurrentMap consumerMap = new ConcurrentHashMap<>(); + private final ExecutorService consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); + private final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); + private final ScheduledExecutorService repartitionExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-repartition")); + public DefaultTbRuleEngineConsumerService(TbRuleEngineProcessingStrategyFactory processingStrategyFactory, TbRuleEngineSubmitStrategyFactory submitStrategyFactory, @@ -153,7 +154,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @PostConstruct public void init() { - super.init("tb-rule-engine-consumer", "tb-rule-engine-notifications-consumer"); + super.init("tb-rule-engine-notifications-consumer"); // TODO: restore init of the main consumer? List queues = queueService.findAllQueues(); for (Queue configuration : queues) { if (partitionService.isManagedByCurrentService(configuration.getTenantId())) { @@ -163,19 +164,14 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private void initConsumer(Queue configuration) { - QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, configuration); - consumerConfigurations.putIfAbsent(queueKey, configuration); - consumerStats.putIfAbsent(queueKey, new TbRuleEngineConsumerStats(configuration, statsFactory)); - if (!configuration.isConsumerPerPartition()) { - consumers.computeIfAbsent(queueKey, queueName -> tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration)); - } else { - topicsConsumerPerPartition.computeIfAbsent(queueKey, k -> new TbTopicWithConsumerPerPartition(k.getQueueName())); - } + consumerMap.computeIfAbsent(new QueueKey(ServiceType.TB_RULE_ENGINE, configuration), + key -> new TbRuleEngineQueueConsumerManager(repartitionExecutor, consumersExecutor, statsFactory, tbRuleEngineQueueFactory, key)).init(configuration); } @PreDestroy public void stop() { super.destroy(); + consumersExecutor.shutdownNow(); // TODO: shutdown or shutdownNow? submitExecutor.shutdownNow(); repartitionExecutor.shutdownNow(); } @@ -183,119 +179,107 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @Override protected void onTbApplicationEvent(PartitionChangeEvent event) { if (event.getServiceType().equals(getServiceType())) { - event.getPartitionsMap().forEach((queueKey, partitions) -> { - String serviceQueue = queueKey.getQueueName(); - log.info("[{}] Subscribing to partitions: {}", serviceQueue, partitions); - Queue configuration = consumerConfigurations.get(queueKey); - if (configuration == null) { - return; - } - if (!configuration.isConsumerPerPartition()) { - consumers.get(queueKey).subscribe(partitions); - } else { - log.info("[{}] Subscribing consumer per partition: {}", serviceQueue, partitions); - subscribeConsumerPerPartition(queueKey, partitions); - } - }); - } - } - - void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { - topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); - scheduleTopicRepartition(queue); - } - - private void scheduleTopicRepartition(QueueKey queue) { - repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); - } - - void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { - if (stopped) { - return; - } - TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); - java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); - if (subscribeQueue.isEmpty()) { - return; - } - if (tbTopicWithConsumerPerPartition.getLock().tryLock()) { - try { - Set partitions = null; - while (!subscribeQueue.isEmpty()) { - partitions = subscribeQueue.poll(); - } - if (partitions == null) { - return; - } - - Set addedPartitions = new HashSet<>(partitions); - ConcurrentMap>> consumers = tbTopicWithConsumerPerPartition.getConsumers(); - addedPartitions.removeAll(consumers.keySet()); - log.info("calculated addedPartitions {}", addedPartitions); - - Set removedPartitions = new HashSet<>(consumers.keySet()); - removedPartitions.removeAll(partitions); - log.info("calculated removedPartitions {}", removedPartitions); - - removedPartitions.forEach((tpi) -> { - removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); - }); - - addedPartitions.forEach((tpi) -> { - log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); - Queue configuration = consumerConfigurations.get(queueKey); - TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); - consumers.put(tpi, consumer); - launchConsumer(consumer, consumerConfigurations.get(queueKey), consumerStats.get(queueKey), "" + queueKey + "-" + tpi.getPartition().orElse(-999999)); - consumer.subscribe(Collections.singleton(tpi)); - }); - } finally { - tbTopicWithConsumerPerPartition.getLock().unlock(); + var consumer = consumerMap.get(event.getQueueKey()); + if (consumer != null) { + consumer.subscribe(event); + } else { + log.warn("Received invalid partition change event for {} that is not managed by this service", event.getQueueKey()); } - } else { - scheduleTopicRepartition(queueKey); //reschedule later } - } +// void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { +// topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); +// scheduleTopicRepartition(queue); +// } +// +// private void scheduleTopicRepartition(QueueKey queue) { +// repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); +// } +// +// void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { +// if (stopped) { +// return; +// } +// TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); +// java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); +// if (subscribeQueue.isEmpty()) { +// return; +// } +// if (tbTopicWithConsumerPerPartition.getLock().tryLock()) { +// try { +// Set partitions = null; +// while (!subscribeQueue.isEmpty()) { +// partitions = subscribeQueue.poll(); +// } +// if (partitions == null) { +// return; +// } +// +// Set addedPartitions = new HashSet<>(partitions); +// ConcurrentMap>> consumers = tbTopicWithConsumerPerPartition.getConsumers(); +// addedPartitions.removeAll(consumers.keySet()); +// log.info("calculated addedPartitions {}", addedPartitions); +// +// Set removedPartitions = new HashSet<>(consumers.keySet()); +// removedPartitions.removeAll(partitions); +// log.info("calculated removedPartitions {}", removedPartitions); +// +// removedPartitions.forEach((tpi) -> { +// removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); +// }); +// +// addedPartitions.forEach((tpi) -> { +// log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); +// Queue configuration = consumerConfigurations.get(queueKey); +// TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); +// consumers.put(tpi, consumer); +// launchConsumer(consumer, queueKey, tpi.getFullTopicName(), queueKey + "-" + tpi.getPartition().orElse(-999999)); +// consumer.subscribe(Collections.singleton(tpi)); +// }); +// } finally { +// tbTopicWithConsumerPerPartition.getLock().unlock(); +// } +// } else { +// scheduleTopicRepartition(queueKey); //reschedule later +// } +// } + void removeConsumerForTopicByTpi(String queue, ConcurrentMap>> consumers, TopicPartitionInfo tpi) { log.info("[{}] Removing consumer for topic: {}", queue, tpi); - consumers.get(tpi).unsubscribe(); - consumers.remove(tpi); + consumers.remove(tpi).stop(); } @Override protected void launchMainConsumers() { - consumers.forEach((queue, consumer) -> launchConsumer(consumer, consumerConfigurations.get(queue), consumerStats.get(queue), queue.getQueueName())); + consumers.forEach((queue, consumer) -> launchConsumer(consumer, queue, queue, queue.getQueueName())); } @Override protected void stopMainConsumers() { - consumers.values().forEach(TbQueueConsumer::unsubscribe); - topicsConsumerPerPartition.values().forEach(tbTopicWithConsumerPerPartition -> tbTopicWithConsumerPerPartition.getConsumers().keySet() - .forEach((tpi) -> removeConsumerForTopicByTpi(tbTopicWithConsumerPerPartition.getTopic(), tbTopicWithConsumerPerPartition.getConsumers(), tpi))); + consumerMap.values().forEach(TbRuleEngineQueueConsumerManager::stop); } - void launchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + void launchConsumer(TbQueueConsumer> consumer, QueueKey queueKey, Object consumerKey, String threadSuffix) { if (isReady) { - consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); + log.info("[{}] Launching consumer", consumerKey); + consumersExecutor.execute(consumerKey, () -> consumerLoop(consumer, queueKey, threadSuffix)); } else { - scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix); + scheduleLaunchConsumer(consumer, queueKey, consumerKey, threadSuffix); } } - private void scheduleLaunchConsumer(TbQueueConsumer> consumer, Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + private void scheduleLaunchConsumer(TbQueueConsumer> consumer, QueueKey queueKey, Object consumerKey, String threadSuffix) { repartitionExecutor.schedule(() -> { - if (isReady) { - consumersExecutor.execute(() -> consumerLoop(consumer, configuration, stats, threadSuffix)); - } else { - scheduleLaunchConsumer(consumer, configuration, stats, threadSuffix); - } + launchConsumer(consumer, queueKey, consumerKey, threadSuffix); }, 10, TimeUnit.SECONDS); } - void consumerLoop(TbQueueConsumer> consumer, org.thingsboard.server.common.data.queue.Queue configuration, TbRuleEngineConsumerStats stats, String threadSuffix) { + void consumerLoop(TbQueueConsumer> consumer, QueueKey queueKey, String threadSuffix) { + Queue configuration = consumerConfigurations.get(queueKey); + TbRuleEngineConsumerStats stats = consumerStats.get(queueKey); updateCurrentThreadName(threadSuffix); + while (!stopped && !consumer.isStopped() && !consumer.isQueueDeleted()) { try { List> msgs = consumer.poll(configuration.getPollInterval()); @@ -347,7 +331,9 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } - if (consumer.isQueueDeleted()) { + if (consumer.isStopped()) { + consumer.unsubscribe(); + } else if (consumer.isQueueDeleted()) { processQueueDeletion(configuration, consumer); } log.info("TB Rule Engine Consumer stopped."); @@ -460,20 +446,20 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< ReentrantLock lock = consumerPerPartition.getLock(); try { lock.lock(); - consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::unsubscribe); + consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::stop); } finally { lock.unlock(); } } else { TbQueueConsumer> consumer = consumers.remove(queueKey); - consumer.unsubscribe(); + consumer.stop(); } } initConsumer(queue); if (!queue.isConsumerPerPartition()) { - launchConsumer(consumers.get(queueKey), consumerConfigurations.get(queueKey), consumerStats.get(queueKey), queueName); + launchConsumer(consumers.get(queueKey), queueKey, queueKey, queueName); } } @@ -502,6 +488,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } } + partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java new file mode 100644 index 0000000000..f5688eb207 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java @@ -0,0 +1,37 @@ +package org.thingsboard.server.service.queue; + +import lombok.Data; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; + +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@Data +public class TbQueueConsumerLauncher { + + private final TbQueueConsumer> consumer; + private volatile Future task; + + public void stop() { + this.consumer.stop(); + } + + public void awaitStopped() throws ExecutionException, InterruptedException, TimeoutException { + if (task != null) { + this.task.get(3, TimeUnit.MINUTES); + } + } + + public void subscribe(Set partitions) { + this.consumer.subscribe(partitions); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java new file mode 100644 index 0000000000..11316a9e05 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java @@ -0,0 +1,17 @@ +package org.thingsboard.server.service.queue; + +import lombok.Data; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; + +import java.util.Set; + +@Data +public class TbQueueConsumerManagerTask { + + private final ComponentLifecycleEvent event; + private final Queue queue; + private final Set partitions; + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java index 2904c299ce..45ccbcf32a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java @@ -25,6 +25,7 @@ import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.common.stats.StatsType; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; import java.util.ArrayList; @@ -66,8 +67,8 @@ public class TbRuleEngineConsumerStats { private final String queueName; private final TenantId tenantId; - public TbRuleEngineConsumerStats(Queue queue, StatsFactory statsFactory) { - this.queueName = queue.getName(); + public TbRuleEngineConsumerStats(QueueKey queue, StatsFactory statsFactory) { + this.queueName = queue.getQueueName(); this.tenantId = queue.getTenantId(); this.statsFactory = statsFactory; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java new file mode 100644 index 0000000000..2c6d191c0a --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java @@ -0,0 +1,205 @@ +package org.thingsboard.server.service.queue; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.common.stats.StatsFactory; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; +import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; + +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +@Data +@Slf4j +public class TbRuleEngineQueueConsumerManager { + + private final ScheduledExecutorService scheduler; + private final ExecutorService consumerExecutor; + private final StatsFactory statsFactory; + private final TbRuleEngineQueueFactory queueFactory; + private final QueueKey key; + private final ReentrantLock lock = new ReentrantLock(); //NonfairSync + private final ConcurrentMap consumers = new ConcurrentHashMap<>(); + private final TbRuleEngineConsumerStats stats; + + private volatile Set partitions = Collections.emptySet(); + private volatile Queue queue; + private volatile TbQueueConsumerLauncher mainConsumer; + + private final java.util.Queue tasks = new ConcurrentLinkedQueue<>(); + + public TbRuleEngineQueueConsumerManager(ScheduledExecutorService scheduler, ExecutorService consumerExecutor, StatsFactory statsFactory, TbRuleEngineQueueFactory queueFactory, QueueKey key) { + this.scheduler = scheduler; + this.consumerExecutor = consumerExecutor; + this.statsFactory = statsFactory; + this.queueFactory = queueFactory; + this.key = key; + this.stats = new TbRuleEngineConsumerStats(key, statsFactory); + } + + public void init(Queue queue) { + processTask(new TbQueueConsumerManagerTask(ComponentLifecycleEvent.CREATED, queue, null)); + } + + private void processTask(TbQueueConsumerManagerTask todo) { + tasks.add(todo); + log.info("[{}] Adding task: {}", key, todo); + tryProcessTasks(); + } + + private void tryProcessTasks() { + consumerExecutor.submit(() -> { + if (lock.tryLock()) { + try { + TbQueueConsumerManagerTask lastUpdateTask = null; + while (!tasks.isEmpty()) { + TbQueueConsumerManagerTask task = tasks.poll(); + switch (task.getEvent()) { + case CREATED: + doInit(task.getQueue()); + break; + case UPDATED: + lastUpdateTask = task; + break; + case DELETED: + lastUpdateTask = null; + doDelete(); + break; + } + } + if (lastUpdateTask != null) { + doUpdate(lastUpdateTask.getQueue(), lastUpdateTask.getPartitions()); + } + } finally { + lock.unlock(); + } + } else { + log.debug("[{}] Failed to acquire lock.", key); + scheduler.schedule(this::tryProcessTasks, 1, TimeUnit.SECONDS); + } + }); + } + + public void doInit(Queue queue) { + log.info("[{}] Init consumer with queue: {}", key, queue); + this.queue = queue; + if (!queue.isConsumerPerPartition()) { + mainConsumer = new TbQueueConsumerLauncher(queueFactory.createToRuleEngineMsgConsumer(queue)); + } + } + + private void doUpdate(Queue newQueue, Set partitions) { + if (newQueue.isConsumerPerPartition()) { + + } else { + for (var oldConsumer : consumers.values()) { + oldConsumer.stop(); + } + for (var oldConsumer : consumers.entrySet()) { + try { + oldConsumer.getValue().awaitStopped(); + } catch (Exception e) { + log.info("[{}][{}] Failed to stop the consumer during update", key, oldConsumer.getKey().getPartition().orElse(-1), e); + } + } + if (mainConsumer == null) { + mainConsumer = new TbQueueConsumerLauncher(queueFactory.createToRuleEngineMsgConsumer(queue)); + //TODO: launch + } + mainConsumer.subscribe(partitions); + + } + } + + private void doDelete() { + } + + public void subscribe(PartitionChangeEvent event) { + log.info("[{}] Subscribing to partitions: {}", key, event.getPartitions()); + if (!queue.isConsumerPerPartition()) { + mainConsumer.subscribe(event.getPartitions()); + } else { + log.info("[{}] Subscribing consumer per partition: {}", key, event.getPartitions()); + subscribeConsumerPerPartition(event.getQueueKey(), event.getPartitions()); + } + } + + void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { + topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); + scheduleTopicRepartition(queue); + } + + private void scheduleTopicRepartition(QueueKey queue) { + repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); + } + + void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { + if (stopped) { + return; + } + TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); + java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); + if (subscribeQueue.isEmpty()) { + return; + } + if (tbTopicWithConsumerPerPartition.getLock().tryLock()) { + try { + Set partitions = null; + while (!subscribeQueue.isEmpty()) { + partitions = subscribeQueue.poll(); + } + if (partitions == null) { + return; + } + + Set addedPartitions = new HashSet<>(partitions); + ConcurrentMap>> consumers = tbTopicWithConsumerPerPartition.getConsumers(); + addedPartitions.removeAll(consumers.keySet()); + log.info("calculated addedPartitions {}", addedPartitions); + + Set removedPartitions = new HashSet<>(consumers.keySet()); + removedPartitions.removeAll(partitions); + log.info("calculated removedPartitions {}", removedPartitions); + + removedPartitions.forEach((tpi) -> { + removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); + }); + + addedPartitions.forEach((tpi) -> { + log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); + Queue configuration = consumerConfigurations.get(queueKey); + TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); + consumers.put(tpi, consumer); + launchConsumer(consumer, queueKey, tpi.getFullTopicName(), queueKey + "-" + tpi.getPartition().orElse(-999999)); + consumer.subscribe(Collections.singleton(tpi)); + }); + } finally { + tbTopicWithConsumerPerPartition.getLock().unlock(); + } + } else { + scheduleTopicRepartition(queueKey); //reschedule later + } + } + + public void stop() { +// consumers.values().forEach(TbQueueConsumer::stop); +// topicsConsumerPerPartition.values().forEach(tbTopicWithConsumerPerPartition -> tbTopicWithConsumerPerPartition.getConsumers().keySet() +// .forEach((tpi) -> removeConsumerForTopicByTpi(tbTopicWithConsumerPerPartition.getTopic(), tbTopicWithConsumerPerPartition.getConsumers(), tpi))); + } + +} diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java index 386447045d..bb1943a7d5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineQueueFactory.java @@ -82,7 +82,6 @@ public interface TbRuleEngineQueueFactory extends TbUsageStatsClientQueueFactory * @return * @param configuration */ - //TODO 2.5 ybondarenko: make sure you use queueName to distinct consumers where necessary TbQueueConsumer> createToRuleEngineMsgConsumer(Queue configuration); /** From 3a0afd8a5ab9e5ed518da6bc1f63f909695875c7 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Mon, 2 Oct 2023 18:51:03 +0300 Subject: [PATCH 208/267] Refactoring of the consumer service --- .../DefaultTbRuleEngineConsumerService.java | 426 ++--------------- .../queue/TbQueueConsumerLauncher.java | 37 -- .../queue/TbQueueConsumerManagerTask.java | 17 - .../TbRuleEngineQueueConsumerManager.java | 205 --------- .../service/queue/ruleengine/QueueEvent.java | 9 + .../TbQueueConsumerManagerTask.java | 32 ++ .../queue/ruleengine/TbQueueConsumerTask.java | 70 +++ .../TbRuleEngineConsumerContext.java | 75 +++ .../TbRuleEngineQueueConsumerManager.java | 431 ++++++++++++++++++ .../common/util/ThingsBoardThreadFactory.java | 12 + 10 files changed, 659 insertions(+), 655 deletions(-) delete mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java delete mode 100644 application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java create mode 100644 application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index ae04de456b..b37e5abff3 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -15,44 +15,25 @@ */ package org.thingsboard.server.service.queue; -import com.google.protobuf.ProtocolStringList; import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.ActorSystemContext; -import org.thingsboard.server.common.data.id.EntityId; -import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rpc.RpcError; -import org.thingsboard.server.common.msg.TbMsg; -import org.thingsboard.server.common.msg.gen.MsgProtos; -import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; -import org.thingsboard.server.common.msg.queue.RuleEngineException; -import org.thingsboard.server.common.msg.queue.RuleNodeInfo; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.common.msg.queue.TbMsgCallback; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.rpc.FromDeviceRpcResponse; -import org.thingsboard.server.common.stats.StatsFactory; -import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; -import org.thingsboard.server.queue.TbQueueAdmin; -import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionService; import org.thingsboard.server.queue.discovery.QueueKey; -import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; -import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; import org.thingsboard.server.queue.util.DataDecodingEncodingService; import org.thingsboard.server.queue.util.TbRuleEngineComponent; @@ -60,102 +41,48 @@ import org.thingsboard.server.service.apiusage.TbApiUsageStateService; import org.thingsboard.server.service.profile.TbAssetProfileCache; import org.thingsboard.server.service.profile.TbDeviceProfileCache; import org.thingsboard.server.service.queue.processing.AbstractConsumerService; -import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDecision; -import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; -import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategy; -import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory; -import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; -import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; +import org.thingsboard.server.service.queue.ruleengine.TbRuleEngineConsumerContext; +import org.thingsboard.server.service.queue.ruleengine.TbRuleEngineQueueConsumerManager; import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; -import org.thingsboard.server.service.stats.RuleEngineStatisticsService; -import org.threadly.concurrent.wrapper.KeyDistributedExecutor; import javax.annotation.PostConstruct; -import javax.annotation.PreDestroy; import java.util.ArrayList; -import java.util.Collections; -import java.util.HashSet; import java.util.List; -import java.util.Map; import java.util.Optional; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; @Service @TbRuleEngineComponent @Slf4j public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService implements TbRuleEngineConsumerService { - public static final String SUCCESSFUL_STATUS = "successful"; - public static final String FAILED_STATUS = "failed"; - public static final String THREAD_TOPIC_SEPARATOR = " | "; - @Value("${queue.rule-engine.poll-interval}") - private long pollDuration; - @Value("${queue.rule-engine.pack-processing-timeout}") - private long packProcessingTimeout; - @Value("${queue.rule-engine.stats.enabled:true}") - private boolean statsEnabled; - @Value("${queue.rule-engine.prometheus-stats.enabled:false}") - boolean prometheusStatsEnabled; - @Value("${queue.rule-engine.topic-deletion-delay:30}") - private int topicDeletionDelayInSec; - - private final StatsFactory statsFactory; - private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory; - private final TbRuleEngineProcessingStrategyFactory processingStrategyFactory; - private final TbRuleEngineQueueFactory tbRuleEngineQueueFactory; - private final RuleEngineStatisticsService statisticsService; + private final TbRuleEngineConsumerContext ctx; private final TbRuleEngineDeviceRpcService tbDeviceRpcService; - private final TbServiceInfoProvider serviceInfoProvider; - private final QueueService queueService; - private final TbQueueProducerProvider producerProvider; - private final TbQueueAdmin queueAdmin; - - private final ConcurrentMap consumerMap = new ConcurrentHashMap<>(); - private final ExecutorService consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); - private final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); - private final ScheduledExecutorService repartitionExecutor = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-repartition")); + private final ConcurrentMap consumers = new ConcurrentHashMap<>(); - public DefaultTbRuleEngineConsumerService(TbRuleEngineProcessingStrategyFactory processingStrategyFactory, - TbRuleEngineSubmitStrategyFactory submitStrategyFactory, + public DefaultTbRuleEngineConsumerService(TbRuleEngineConsumerContext ctx, TbRuleEngineQueueFactory tbRuleEngineQueueFactory, - RuleEngineStatisticsService statisticsService, ActorSystemContext actorContext, DataDecodingEncodingService encodingService, TbRuleEngineDeviceRpcService tbDeviceRpcService, - StatsFactory statsFactory, TbDeviceProfileCache deviceProfileCache, TbAssetProfileCache assetProfileCache, TbTenantProfileCache tenantProfileCache, TbApiUsageStateService apiUsageStateService, - PartitionService partitionService, ApplicationEventPublisher eventPublisher, - TbServiceInfoProvider serviceInfoProvider, QueueService queueService, - TbQueueProducerProvider producerProvider, TbQueueAdmin queueAdmin) { - super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); - this.statisticsService = statisticsService; - this.tbRuleEngineQueueFactory = tbRuleEngineQueueFactory; - this.submitStrategyFactory = submitStrategyFactory; - this.processingStrategyFactory = processingStrategyFactory; + PartitionService partitionService, ApplicationEventPublisher eventPublisher) { + super(actorContext, encodingService, tenantProfileCache, deviceProfileCache, assetProfileCache, apiUsageStateService, partitionService, + eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); + this.ctx = ctx; this.tbDeviceRpcService = tbDeviceRpcService; - this.statsFactory = statsFactory; - this.serviceInfoProvider = serviceInfoProvider; - this.queueService = queueService; - this.producerProvider = producerProvider; - this.queueAdmin = queueAdmin; } @PostConstruct public void init() { super.init("tb-rule-engine-notifications-consumer"); // TODO: restore init of the main consumer? - List queues = queueService.findAllQueues(); + List queues = ctx.findAllQueues(); for (Queue configuration : queues) { if (partitionService.isManagedByCurrentService(configuration.getTenantId())) { initConsumer(configuration); @@ -164,22 +91,14 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private void initConsumer(Queue configuration) { - consumerMap.computeIfAbsent(new QueueKey(ServiceType.TB_RULE_ENGINE, configuration), - key -> new TbRuleEngineQueueConsumerManager(repartitionExecutor, consumersExecutor, statsFactory, tbRuleEngineQueueFactory, key)).init(configuration); - } - - @PreDestroy - public void stop() { - super.destroy(); - consumersExecutor.shutdownNow(); // TODO: shutdown or shutdownNow? - submitExecutor.shutdownNow(); - repartitionExecutor.shutdownNow(); + consumers.computeIfAbsent(new QueueKey(ServiceType.TB_RULE_ENGINE, configuration), + key -> new TbRuleEngineQueueConsumerManager(ctx, key)).init(configuration); } @Override protected void onTbApplicationEvent(PartitionChangeEvent event) { if (event.getServiceType().equals(getServiceType())) { - var consumer = consumerMap.get(event.getQueueKey()); + var consumer = consumers.get(event.getQueueKey()); if (consumer != null) { consumer.subscribe(event); } else { @@ -188,207 +107,14 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } } -// void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { -// topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); -// scheduleTopicRepartition(queue); -// } -// -// private void scheduleTopicRepartition(QueueKey queue) { -// repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); -// } -// -// void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { -// if (stopped) { -// return; -// } -// TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); -// java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); -// if (subscribeQueue.isEmpty()) { -// return; -// } -// if (tbTopicWithConsumerPerPartition.getLock().tryLock()) { -// try { -// Set partitions = null; -// while (!subscribeQueue.isEmpty()) { -// partitions = subscribeQueue.poll(); -// } -// if (partitions == null) { -// return; -// } -// -// Set addedPartitions = new HashSet<>(partitions); -// ConcurrentMap>> consumers = tbTopicWithConsumerPerPartition.getConsumers(); -// addedPartitions.removeAll(consumers.keySet()); -// log.info("calculated addedPartitions {}", addedPartitions); -// -// Set removedPartitions = new HashSet<>(consumers.keySet()); -// removedPartitions.removeAll(partitions); -// log.info("calculated removedPartitions {}", removedPartitions); -// -// removedPartitions.forEach((tpi) -> { -// removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); -// }); -// -// addedPartitions.forEach((tpi) -> { -// log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); -// Queue configuration = consumerConfigurations.get(queueKey); -// TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); -// consumers.put(tpi, consumer); -// launchConsumer(consumer, queueKey, tpi.getFullTopicName(), queueKey + "-" + tpi.getPartition().orElse(-999999)); -// consumer.subscribe(Collections.singleton(tpi)); -// }); -// } finally { -// tbTopicWithConsumerPerPartition.getLock().unlock(); -// } -// } else { -// scheduleTopicRepartition(queueKey); //reschedule later -// } -// } - - void removeConsumerForTopicByTpi(String queue, ConcurrentMap>> consumers, TopicPartitionInfo tpi) { - log.info("[{}] Removing consumer for topic: {}", queue, tpi); - consumers.remove(tpi).stop(); - } - @Override protected void launchMainConsumers() { - consumers.forEach((queue, consumer) -> launchConsumer(consumer, queue, queue, queue.getQueueName())); + consumers.values().forEach(TbRuleEngineQueueConsumerManager::launchMainConsumer); } @Override protected void stopMainConsumers() { - consumerMap.values().forEach(TbRuleEngineQueueConsumerManager::stop); - } - - void launchConsumer(TbQueueConsumer> consumer, QueueKey queueKey, Object consumerKey, String threadSuffix) { - if (isReady) { - log.info("[{}] Launching consumer", consumerKey); - consumersExecutor.execute(consumerKey, () -> consumerLoop(consumer, queueKey, threadSuffix)); - } else { - scheduleLaunchConsumer(consumer, queueKey, consumerKey, threadSuffix); - } - } - - private void scheduleLaunchConsumer(TbQueueConsumer> consumer, QueueKey queueKey, Object consumerKey, String threadSuffix) { - repartitionExecutor.schedule(() -> { - launchConsumer(consumer, queueKey, consumerKey, threadSuffix); - }, 10, TimeUnit.SECONDS); - } - - void consumerLoop(TbQueueConsumer> consumer, QueueKey queueKey, String threadSuffix) { - Queue configuration = consumerConfigurations.get(queueKey); - TbRuleEngineConsumerStats stats = consumerStats.get(queueKey); - updateCurrentThreadName(threadSuffix); - - while (!stopped && !consumer.isStopped() && !consumer.isQueueDeleted()) { - try { - List> msgs = consumer.poll(configuration.getPollInterval()); - if (msgs.isEmpty()) { - continue; - } - final TbRuleEngineSubmitStrategy submitStrategy = getSubmitStrategy(configuration); - final TbRuleEngineProcessingStrategy ackStrategy = getAckStrategy(configuration); - submitStrategy.init(msgs); - while (!stopped && !consumer.isStopped()) { - TbMsgPackProcessingContext ctx = new TbMsgPackProcessingContext(configuration.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); - submitStrategy.submitAttempt((id, msg) -> submitExecutor.submit(() -> submitMessage(configuration, stats, ctx, id, msg))); - - final boolean timeout = !ctx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); - - TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, ctx); - if (timeout) { - printFirstOrAll(configuration, ctx, ctx.getPendingMap(), "Timeout"); - } - if (!ctx.getFailedMap().isEmpty()) { - printFirstOrAll(configuration, ctx, ctx.getFailedMap(), "Failed"); - } - ctx.printProfilerStats(); - - TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); - if (statsEnabled) { - stats.log(result, decision.isCommit()); - } - - ctx.cleanup(); - - if (decision.isCommit()) { - submitStrategy.stop(); - break; - } else { - submitStrategy.update(decision.getReprocessMap()); - } - } - consumer.commit(); - } catch (Exception e) { - if (!stopped) { - log.warn("Failed to process messages from queue.", e); - try { - Thread.sleep(pollDuration); - } catch (InterruptedException e2) { - log.trace("Failed to wait until the server has capacity to handle new requests", e2); - } - } - } - } - - if (consumer.isStopped()) { - consumer.unsubscribe(); - } else if (consumer.isQueueDeleted()) { - processQueueDeletion(configuration, consumer); - } - log.info("TB Rule Engine Consumer stopped."); - } - - void updateCurrentThreadName(String threadSuffix) { - String name = Thread.currentThread().getName(); - int spliteratorIndex = name.indexOf(THREAD_TOPIC_SEPARATOR); - if (spliteratorIndex > 0) { - name = name.substring(0, spliteratorIndex); - } - name = name + THREAD_TOPIC_SEPARATOR + threadSuffix; - Thread.currentThread().setName(name); - } - - TbRuleEngineProcessingStrategy getAckStrategy(Queue configuration) { - return processingStrategyFactory.newInstance(configuration.getName(), configuration.getProcessingStrategy()); - } - - TbRuleEngineSubmitStrategy getSubmitStrategy(Queue configuration) { - return submitStrategyFactory.newInstance(configuration.getName(), configuration.getSubmitStrategy()); - } - - void submitMessage(Queue configuration, TbRuleEngineConsumerStats stats, TbMsgPackProcessingContext ctx, UUID id, TbProtoQueueMsg msg) { - log.trace("[{}] Creating callback for topic {} message: {}", id, configuration.getName(), msg.getValue()); - ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); - 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); - try { - if (toRuleEngineMsg.getTbMsg() != null && !toRuleEngineMsg.getTbMsg().isEmpty()) { - forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); - } else { - callback.onSuccess(); - } - } catch (Exception e) { - callback.onFailure(new RuleEngineException(e.getMessage(), e)); - } - } - - private void printFirstOrAll(Queue configuration, TbMsgPackProcessingContext ctx, Map> map, String prefix) { - boolean printAll = log.isTraceEnabled(); - log.info("{} to process [{}] messages", prefix, map.size()); - for (Map.Entry> pending : map.entrySet()) { - ToRuleEngineMsg tmp = pending.getValue().getValue(); - 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: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); - } else { - log.info("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); - break; - } - } + consumers.values().forEach(TbRuleEngineQueueConsumerManager::stop); } @Override @@ -398,18 +124,18 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @Override protected long getNotificationPollDuration() { - return pollDuration; + return ctx.getPollDuration(); } @Override protected long getNotificationPackProcessingTimeout() { - return packProcessingTimeout; + return ctx.getPackProcessingTimeout(); } @Override protected void handleNotification(UUID id, TbProtoQueueMsg msg, TbCallback callback) throws Exception { ToRuleEngineNotificationMsg nfMsg = msg.getValue(); - if (nfMsg.getComponentLifecycleMsg() != null && !nfMsg.getComponentLifecycleMsg().isEmpty()) { + if (!nfMsg.getComponentLifecycleMsg().isEmpty()) { handleComponentLifecycleMsg(id, nfMsg.getComponentLifecycleMsg()); callback.onSuccess(); } else if (nfMsg.hasFromDeviceRpcResponse()) { @@ -420,10 +146,10 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< tbDeviceRpcService.processRpcResponseFromDevice(response); callback.onSuccess(); } else if (nfMsg.hasQueueUpdateMsg()) { - repartitionExecutor.execute(() -> updateQueue(nfMsg.getQueueUpdateMsg())); + ctx.getScheduler().execute(() -> updateQueue(nfMsg.getQueueUpdateMsg())); callback.onSuccess(); } else if (nfMsg.hasQueueDeleteMsg()) { - repartitionExecutor.execute(() -> deleteQueue(nfMsg.getQueueDeleteMsg())); + ctx.getScheduler().execute(() -> deleteQueue(nfMsg.getQueueDeleteMsg())); callback.onSuccess(); } else { log.trace("Received notification with missing handler"); @@ -438,33 +164,13 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); String queueName = queueUpdateMsg.getQueueName(); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueName, tenantId); - Queue queue = queueService.findQueueById(tenantId, queueId); - Queue oldQueue = consumerConfigurations.remove(queueKey); - if (oldQueue != null) { - if (oldQueue.isConsumerPerPartition()) { - TbTopicWithConsumerPerPartition consumerPerPartition = topicsConsumerPerPartition.remove(queueKey); - ReentrantLock lock = consumerPerPartition.getLock(); - try { - lock.lock(); - consumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::stop); - } finally { - lock.unlock(); - } - } else { - TbQueueConsumer> consumer = consumers.remove(queueKey); - consumer.stop(); - } - } - - initConsumer(queue); - - if (!queue.isConsumerPerPartition()) { - launchConsumer(consumers.get(queueKey), queueKey, queueKey, queueName); - } + Queue queue = ctx.getQueueService().findQueueById(tenantId, queueId); + consumers.computeIfAbsent(queueKey, key -> new TbRuleEngineQueueConsumerManager(ctx, key)).update(queue); } partitionService.updateQueue(queueUpdateMsg); - partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); + partitionService.recalculatePartitions(ctx.getServiceInfoProvider().getServiceInfo(), + new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } private void deleteQueue(TransportProtos.QueueDeleteMsg queueDeleteMsg) { @@ -473,90 +179,18 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); partitionService.removeQueue(queueDeleteMsg); - Queue queue = consumerConfigurations.remove(queueKey); - if (queue != null) { - if (queue.isConsumerPerPartition()) { - TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.remove(queueKey); - if (tbTopicWithConsumerPerPartition != null) { - tbTopicWithConsumerPerPartition.getConsumers().values().forEach(TbQueueConsumer::onQueueDelete); - tbTopicWithConsumerPerPartition.getConsumers().clear(); - } - } else { - TbQueueConsumer> consumer = consumers.remove(queueKey); - if (consumer != null) { - consumer.onQueueDelete(); - } - } - } - partitionService.recalculatePartitions(serviceInfoProvider.getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); - } - - private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { - TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback); - QueueToRuleEngineMsg msg; - ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); - Set relationTypes = null; - if (relationTypesList != null) { - if (relationTypesList.size() == 1) { - relationTypes = Collections.singleton(relationTypesList.get(0)); - } else { - relationTypes = new HashSet<>(relationTypesList); - } - } - msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); - actorContext.tell(msg); - } - - private void processQueueDeletion(Queue queue, TbQueueConsumer> consumer) { - long finishTs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(topicDeletionDelayInSec); - try { - int n = 0; - while (System.currentTimeMillis() <= finishTs) { - List> msgs = consumer.poll(queue.getPollInterval()); - if (msgs.isEmpty()) { - continue; - } - for (TbProtoQueueMsg msg : msgs) { - try { - MsgProtos.TbMsgProto tbMsgProto = MsgProtos.TbMsgProto.parseFrom(msg.getValue().getTbMsg().toByteArray()); - EntityId originator = EntityIdFactory.getByTypeAndUuid(tbMsgProto.getEntityType(), new UUID(tbMsgProto.getEntityIdMSB(), tbMsgProto.getEntityIdLSB())); - - TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, queue.getName(), TenantId.SYS_TENANT_ID, originator); - producerProvider.getRuleEngineMsgProducer().send(tpi, msg, null); - n++; - } catch (Throwable e) { - log.debug("Failed to move message to system {}: {}", consumer.getTopic(), msg, e); - } - } - consumer.commit(); - } - if (n > 0) { - log.info("Moved {} messages from {} to system {}", n, consumer.getFullTopicNames(), consumer.getTopic()); - } - - consumer.unsubscribe(); - for (String topic : consumer.getFullTopicNames()) { - try { - queueAdmin.deleteTopic(topic); - log.info("Deleted topic {}", topic); - } catch (Exception e) { - log.error("Failed to delete topic {} after unsubscribing", topic, e); - } - } - } catch (Exception e) { - log.error("Failed to process deletion of {} ({})", consumer.getTopic(), queue.getTenantId(), e); + var manager = consumers.remove(queueKey); + if (manager != null) { + manager.delete(); } + partitionService.recalculatePartitions(ctx.getServiceInfoProvider().getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") public void printStats() { - if (statsEnabled) { + if (ctx.isStatsEnabled()) { long ts = System.currentTimeMillis(); - consumerStats.forEach((queue, stats) -> { - stats.printStats(); - statisticsService.reportQueueStats(ts, stats); - stats.reset(); - }); + consumers.values().forEach(manager -> manager.printStats(ts)); } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java deleted file mode 100644 index f5688eb207..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerLauncher.java +++ /dev/null @@ -1,37 +0,0 @@ -package org.thingsboard.server.service.queue; - -import lombok.Data; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; -import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.queue.TbQueueConsumer; -import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.QueueKey; - -import java.util.Set; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -@Data -public class TbQueueConsumerLauncher { - - private final TbQueueConsumer> consumer; - private volatile Future task; - - public void stop() { - this.consumer.stop(); - } - - public void awaitStopped() throws ExecutionException, InterruptedException, TimeoutException { - if (task != null) { - this.task.get(3, TimeUnit.MINUTES); - } - } - - public void subscribe(Set partitions) { - this.consumer.subscribe(partitions); - } -} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java deleted file mode 100644 index 11316a9e05..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbQueueConsumerManagerTask.java +++ /dev/null @@ -1,17 +0,0 @@ -package org.thingsboard.server.service.queue; - -import lombok.Data; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; - -import java.util.Set; - -@Data -public class TbQueueConsumerManagerTask { - - private final ComponentLifecycleEvent event; - private final Queue queue; - private final Set partitions; - -} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java deleted file mode 100644 index 2c6d191c0a..0000000000 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineQueueConsumerManager.java +++ /dev/null @@ -1,205 +0,0 @@ -package org.thingsboard.server.service.queue; - -import lombok.Data; -import lombok.extern.slf4j.Slf4j; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; -import org.thingsboard.server.common.data.queue.Queue; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; -import org.thingsboard.server.common.stats.StatsFactory; -import org.thingsboard.server.gen.transport.TransportProtos; -import org.thingsboard.server.queue.TbQueueConsumer; -import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.QueueKey; -import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; -import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.locks.ReentrantLock; - -@Data -@Slf4j -public class TbRuleEngineQueueConsumerManager { - - private final ScheduledExecutorService scheduler; - private final ExecutorService consumerExecutor; - private final StatsFactory statsFactory; - private final TbRuleEngineQueueFactory queueFactory; - private final QueueKey key; - private final ReentrantLock lock = new ReentrantLock(); //NonfairSync - private final ConcurrentMap consumers = new ConcurrentHashMap<>(); - private final TbRuleEngineConsumerStats stats; - - private volatile Set partitions = Collections.emptySet(); - private volatile Queue queue; - private volatile TbQueueConsumerLauncher mainConsumer; - - private final java.util.Queue tasks = new ConcurrentLinkedQueue<>(); - - public TbRuleEngineQueueConsumerManager(ScheduledExecutorService scheduler, ExecutorService consumerExecutor, StatsFactory statsFactory, TbRuleEngineQueueFactory queueFactory, QueueKey key) { - this.scheduler = scheduler; - this.consumerExecutor = consumerExecutor; - this.statsFactory = statsFactory; - this.queueFactory = queueFactory; - this.key = key; - this.stats = new TbRuleEngineConsumerStats(key, statsFactory); - } - - public void init(Queue queue) { - processTask(new TbQueueConsumerManagerTask(ComponentLifecycleEvent.CREATED, queue, null)); - } - - private void processTask(TbQueueConsumerManagerTask todo) { - tasks.add(todo); - log.info("[{}] Adding task: {}", key, todo); - tryProcessTasks(); - } - - private void tryProcessTasks() { - consumerExecutor.submit(() -> { - if (lock.tryLock()) { - try { - TbQueueConsumerManagerTask lastUpdateTask = null; - while (!tasks.isEmpty()) { - TbQueueConsumerManagerTask task = tasks.poll(); - switch (task.getEvent()) { - case CREATED: - doInit(task.getQueue()); - break; - case UPDATED: - lastUpdateTask = task; - break; - case DELETED: - lastUpdateTask = null; - doDelete(); - break; - } - } - if (lastUpdateTask != null) { - doUpdate(lastUpdateTask.getQueue(), lastUpdateTask.getPartitions()); - } - } finally { - lock.unlock(); - } - } else { - log.debug("[{}] Failed to acquire lock.", key); - scheduler.schedule(this::tryProcessTasks, 1, TimeUnit.SECONDS); - } - }); - } - - public void doInit(Queue queue) { - log.info("[{}] Init consumer with queue: {}", key, queue); - this.queue = queue; - if (!queue.isConsumerPerPartition()) { - mainConsumer = new TbQueueConsumerLauncher(queueFactory.createToRuleEngineMsgConsumer(queue)); - } - } - - private void doUpdate(Queue newQueue, Set partitions) { - if (newQueue.isConsumerPerPartition()) { - - } else { - for (var oldConsumer : consumers.values()) { - oldConsumer.stop(); - } - for (var oldConsumer : consumers.entrySet()) { - try { - oldConsumer.getValue().awaitStopped(); - } catch (Exception e) { - log.info("[{}][{}] Failed to stop the consumer during update", key, oldConsumer.getKey().getPartition().orElse(-1), e); - } - } - if (mainConsumer == null) { - mainConsumer = new TbQueueConsumerLauncher(queueFactory.createToRuleEngineMsgConsumer(queue)); - //TODO: launch - } - mainConsumer.subscribe(partitions); - - } - } - - private void doDelete() { - } - - public void subscribe(PartitionChangeEvent event) { - log.info("[{}] Subscribing to partitions: {}", key, event.getPartitions()); - if (!queue.isConsumerPerPartition()) { - mainConsumer.subscribe(event.getPartitions()); - } else { - log.info("[{}] Subscribing consumer per partition: {}", key, event.getPartitions()); - subscribeConsumerPerPartition(event.getQueueKey(), event.getPartitions()); - } - } - - void subscribeConsumerPerPartition(QueueKey queue, Set partitions) { - topicsConsumerPerPartition.get(queue).getSubscribeQueue().add(partitions); - scheduleTopicRepartition(queue); - } - - private void scheduleTopicRepartition(QueueKey queue) { - repartitionExecutor.schedule(() -> repartitionTopicWithConsumerPerPartition(queue), 1, TimeUnit.SECONDS); - } - - void repartitionTopicWithConsumerPerPartition(final QueueKey queueKey) { - if (stopped) { - return; - } - TbTopicWithConsumerPerPartition tbTopicWithConsumerPerPartition = topicsConsumerPerPartition.get(queueKey); - java.util.Queue> subscribeQueue = tbTopicWithConsumerPerPartition.getSubscribeQueue(); - if (subscribeQueue.isEmpty()) { - return; - } - if (tbTopicWithConsumerPerPartition.getLock().tryLock()) { - try { - Set partitions = null; - while (!subscribeQueue.isEmpty()) { - partitions = subscribeQueue.poll(); - } - if (partitions == null) { - return; - } - - Set addedPartitions = new HashSet<>(partitions); - ConcurrentMap>> consumers = tbTopicWithConsumerPerPartition.getConsumers(); - addedPartitions.removeAll(consumers.keySet()); - log.info("calculated addedPartitions {}", addedPartitions); - - Set removedPartitions = new HashSet<>(consumers.keySet()); - removedPartitions.removeAll(partitions); - log.info("calculated removedPartitions {}", removedPartitions); - - removedPartitions.forEach((tpi) -> { - removeConsumerForTopicByTpi(queueKey.getQueueName(), consumers, tpi); - }); - - addedPartitions.forEach((tpi) -> { - log.info("[{}] Adding consumer for topic: {}", queueKey, tpi); - Queue configuration = consumerConfigurations.get(queueKey); - TbQueueConsumer> consumer = tbRuleEngineQueueFactory.createToRuleEngineMsgConsumer(configuration); - consumers.put(tpi, consumer); - launchConsumer(consumer, queueKey, tpi.getFullTopicName(), queueKey + "-" + tpi.getPartition().orElse(-999999)); - consumer.subscribe(Collections.singleton(tpi)); - }); - } finally { - tbTopicWithConsumerPerPartition.getLock().unlock(); - } - } else { - scheduleTopicRepartition(queueKey); //reschedule later - } - } - - public void stop() { -// consumers.values().forEach(TbQueueConsumer::stop); -// topicsConsumerPerPartition.values().forEach(tbTopicWithConsumerPerPartition -> tbTopicWithConsumerPerPartition.getConsumers().keySet() -// .forEach((tpi) -> removeConsumerForTopicByTpi(tbTopicWithConsumerPerPartition.getTopic(), tbTopicWithConsumerPerPartition.getConsumers(), tpi))); - } - -} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java new file mode 100644 index 0000000000..4d01d15d9a --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java @@ -0,0 +1,9 @@ +package org.thingsboard.server.service.queue.ruleengine; + +import java.io.Serializable; + +public enum QueueEvent implements Serializable { + + CREATED, LAUNCHED, UPDATED, PARTITION_CHANGE, STOP, DELETED + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java new file mode 100644 index 0000000000..5b4f164a10 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java @@ -0,0 +1,32 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; + +import lombok.Data; +import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; + +import java.util.Set; + +@Data +public class TbQueueConsumerManagerTask { + + private final QueueEvent event; + private final Queue queue; + private final Set partitions; + +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java new file mode 100644 index 0000000000..3f549b273c --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java @@ -0,0 +1,70 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; + +import java.util.Set; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; + +@Data +@Slf4j +public class TbQueueConsumerTask { + + private final QueueKey key; + private final Object id; + private final TbQueueConsumer> consumer; + private volatile Future task; + + public void stop() { + this.consumer.stop(); + } + + public boolean stopAndAwait() { + this.consumer.stop(); + return await(); + } + + public boolean await() { + if (task != null) { + try { + this.task.get(3, TimeUnit.MINUTES); + } catch (ExecutionException | InterruptedException | TimeoutException e) { + log.warn("[{}][{}] Failed to await for consumer to stop", key, id, e); + return false; + } + } + return true; + } + + public void subscribe(Set partitions) { + this.consumer.subscribe(partitions); + } + + + public void unsubscribe() { + this.consumer.unsubscribe(); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java new file mode 100644 index 0000000000..49f1ad1fab --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -0,0 +1,75 @@ +package org.thingsboard.server.service.queue.ruleengine; + +import lombok.Data; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.actors.ActorSystemContext; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.stats.StatsFactory; +import org.thingsboard.server.dao.queue.QueueService; +import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.provider.TbQueueProducerProvider; +import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; +import org.thingsboard.server.queue.util.TbRuleEngineComponent; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory; +import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; +import org.thingsboard.server.service.rpc.TbRuleEngineDeviceRpcService; +import org.thingsboard.server.service.stats.RuleEngineStatisticsService; + +import javax.annotation.PreDestroy; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; + +@Component +@TbRuleEngineComponent +@Slf4j +@Data +public class TbRuleEngineConsumerContext { + + @Value("${queue.rule-engine.poll-interval}") + private long pollDuration; + @Value("${queue.rule-engine.pack-processing-timeout}") + private long packProcessingTimeout; + @Value("${queue.rule-engine.stats.enabled:true}") + private boolean statsEnabled; + @Value("${queue.rule-engine.prometheus-stats.enabled:false}") + boolean prometheusStatsEnabled; + @Value("${queue.rule-engine.topic-deletion-delay:30}") + private int topicDeletionDelayInSec; + + protected volatile boolean stopped = false; + protected volatile boolean isReady = false; + + private final ActorSystemContext actorContext; + private final StatsFactory statsFactory; + private final TbRuleEngineSubmitStrategyFactory submitStrategyFactory; + private final TbRuleEngineProcessingStrategyFactory processingStrategyFactory; + private final TbRuleEngineQueueFactory queueFactory; + private final RuleEngineStatisticsService statisticsService; + private final TbServiceInfoProvider serviceInfoProvider; + private final QueueService queueService; + private final TbQueueProducerProvider producerProvider; + private final TbQueueAdmin queueAdmin; + + //TODO: add reasonable limit for mgmt pool. + private final ExecutorService mgmtExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-mgmt")); + private final ExecutorService consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); + private final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); + private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-scheduler")); + + public List findAllQueues() { + return queueService.findAllQueues(); + } + + @PreDestroy + public void stop() { + consumersExecutor.shutdownNow(); // TODO: shutdown or shutdownNow? + submitExecutor.shutdownNow(); + scheduler.shutdownNow(); + } +} diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java new file mode 100644 index 0000000000..2599a214f0 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java @@ -0,0 +1,431 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; + +import com.google.protobuf.ProtocolStringList; +import lombok.Data; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.thingsboard.common.util.ThingsBoardThreadFactory; +import org.thingsboard.server.common.data.id.EntityId; +import org.thingsboard.server.common.data.id.EntityIdFactory; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.gen.MsgProtos; +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; +import org.thingsboard.server.common.msg.queue.RuleEngineException; +import org.thingsboard.server.common.msg.queue.RuleNodeInfo; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.msg.queue.TbMsgCallback; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.queue.TbQueueConsumer; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; +import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; +import org.thingsboard.server.service.queue.TbMsgPackCallback; +import org.thingsboard.server.service.queue.TbMsgPackProcessingContext; +import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingDecision; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategy; +import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; + +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.ReentrantLock; + +@Data +@Slf4j +public class TbRuleEngineQueueConsumerManager { + + public static final String SUCCESSFUL_STATUS = "successful"; + public static final String FAILED_STATUS = "failed"; + + private final TbRuleEngineConsumerContext ctx; + private final QueueKey key; + + private final ReentrantLock lock = new ReentrantLock(); //NonfairSync + private final ConcurrentMap consumersPerPartition = new ConcurrentHashMap<>(); + private final TbRuleEngineConsumerStats stats; + + private volatile Set partitions = Collections.emptySet(); + private volatile Queue queue; + private volatile TbQueueConsumerTask mainConsumer; + + private final java.util.Queue tasks = new ConcurrentLinkedQueue<>(); + + public TbRuleEngineQueueConsumerManager(TbRuleEngineConsumerContext ctx, QueueKey key) { + this.ctx = ctx; + this.key = key; + this.stats = new TbRuleEngineConsumerStats(key, ctx.getStatsFactory()); + } + + public void init(Queue queue) { + processTask(new TbQueueConsumerManagerTask(QueueEvent.CREATED, queue, null)); + } + + public void update(Queue queue) { + processTask(new TbQueueConsumerManagerTask(QueueEvent.UPDATED, queue, null)); + } + + public void subscribe(PartitionChangeEvent event) { + processTask(new TbQueueConsumerManagerTask(QueueEvent.PARTITION_CHANGE, queue, event.getPartitions())); + } + + public void launchMainConsumer() { + processTask(new TbQueueConsumerManagerTask(QueueEvent.LAUNCHED, null, null)); + } + + public void stop() { + processTask(new TbQueueConsumerManagerTask(QueueEvent.STOP, null, null)); + } + + public void delete() { + processTask(new TbQueueConsumerManagerTask(QueueEvent.DELETED, null, null)); + } + + private void processTask(TbQueueConsumerManagerTask todo) { + tasks.add(todo); + log.info("[{}] Adding task: {}", key, todo); + tryProcessTasks(); + } + + private void tryProcessTasks() { + ctx.getMgmtExecutor().submit(() -> { + if (lock.tryLock()) { + try { + Queue newConfiguration = null; + Set newPartitions = null; + while (!tasks.isEmpty()) { + TbQueueConsumerManagerTask task = tasks.poll(); + switch (task.getEvent()) { + case CREATED: + doInit(task.getQueue()); + break; + case LAUNCHED: + if (!queue.isConsumerPerPartition()) { + doLaunchMainConsumer(); + } + break; + case UPDATED: + newConfiguration = task.getQueue(); + break; + case PARTITION_CHANGE: + newPartitions = task.getPartitions(); + break; + case STOP: + newConfiguration = null; + newPartitions = null; + doStop(); + break; + case DELETED: + newConfiguration = null; + newPartitions = null; + doDelete(); + break; + } + } + if (newConfiguration != null) { + doUpdate(newConfiguration); + } + if (newPartitions != null) { + doUpdate(newPartitions); + } + } finally { + lock.unlock(); + } + } else { + log.debug("[{}] Failed to acquire lock.", key); + ctx.getScheduler().schedule(this::tryProcessTasks, 1, TimeUnit.SECONDS); + } + }); + } + + public void doInit(Queue queue) { + log.info("[{}] Init consumer with queue: {}", key, queue); + this.queue = queue; + if (queue.isConsumerPerPartition()) { + log.debug("[{}] Ignore init event since isConsumerPerPartition is enabled.", key); + } else { + mainConsumer = new TbQueueConsumerTask(key, "main", ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); + } + } + + private void doLaunchMainConsumer() { + if (mainConsumer != null) { + launchConsumer(mainConsumer, queue, mainConsumer.getId(), queue.getName()); + } else { + log.warn("[{}] Can't launch main consumer since it is empty!", key); + } + } + + private void doUpdate(Queue newQueue) { + log.info("[{}] Processing queue update: {}", key, newQueue); + var oldQueue = queue; + if (log.isTraceEnabled()) { + log.trace("[{}] Old queue configuration: {}", key, oldQueue); + log.trace("[{}] New queue configuration: {}", key, newQueue); + } + if (oldQueue != null) { + doStop(oldQueue); + } + doInit(newQueue); + if (!newQueue.isConsumerPerPartition()) { + doLaunchMainConsumer(); + } + } + + private void doUpdate(Set partitions) { + log.info("[{}] Subscribing to partitions: {}", key, partitions); + if (queue.isConsumerPerPartition()) { + log.debug("[{}] Subscribing consumers per partition separately: {}", key, partitions); + Set addedPartitions = new HashSet<>(partitions); + addedPartitions.removeAll(consumersPerPartition.keySet()); + log.info("calculated addedPartitions {}", addedPartitions); + + Set removedPartitions = new HashSet<>(consumersPerPartition.keySet()); + removedPartitions.removeAll(partitions); + log.info("calculated removedPartitions {}", removedPartitions); + + removedPartitions.forEach((tpi) -> { + log.info("[{}] Unsubscribing from topic: {}", queue, tpi); + consumersPerPartition.get(tpi).unsubscribe(); + }); + + removedPartitions.forEach((tpi) -> { + log.info("[{}] Removing consumer for topic: {}", queue, tpi); + consumersPerPartition.get(tpi).stopAndAwait(); + consumersPerPartition.remove(tpi); + }); + + addedPartitions.forEach((tpi) -> { + log.info("[{}] Adding consumer for topic: {}", key, tpi); + TbQueueConsumerTask consumerTask = new TbQueueConsumerTask(key, tpi, ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); + consumersPerPartition.put(tpi, consumerTask); + //TODO: Is it ok to subscribe first? + consumerTask.subscribe(Collections.singleton(tpi)); + launchConsumer(consumerTask, queue, mainConsumer.getId(), key + "-" + tpi.getPartition().orElse(-999999)); + }); + } else { + mainConsumer.subscribe(partitions); + } + } + + private void doStop() { + doStop(queue); + } + + private void doStop(Queue queue) { + if (queue.isConsumerPerPartition()) { + consumersPerPartition.values().forEach(TbQueueConsumerTask::unsubscribe); + consumersPerPartition.values().forEach(TbQueueConsumerTask::stopAndAwait); + } else if (mainConsumer != null) { + mainConsumer.unsubscribe(); + mainConsumer.stopAndAwait(); + } + } + + private void doDelete() { + doStop(); + //TODO: repack messages + } + + @SneakyThrows + void launchConsumer(TbQueueConsumerTask consumerTask, Queue configuration, Object consumerKey, String threadSuffix) { + log.info("[{}] Launching consumer: [{}]", key, consumerKey); + while (!ctx.isReady) { + //TODO: Remember this task. Cancel previous task if needed. + log.debug("[{}][{}] Waiting for consumer to get ready..", key, consumerKey); + Thread.sleep(1000); + } + consumerTask.setTask(ctx.getConsumersExecutor().submit(() -> consumerLoop(consumerTask.getConsumer(), configuration, threadSuffix))); + } + + void consumerLoop(TbQueueConsumer> consumer, Queue configuration, String threadSuffix) { + ThingsBoardThreadFactory.updateCurrentThreadName(threadSuffix); + while (!ctx.stopped && !consumer.isStopped() + //TODO: remove this. + && !consumer.isQueueDeleted()) { + try { + List> msgs = consumer.poll(queue.getPollInterval()); + if (msgs.isEmpty()) { + continue; + } + final TbRuleEngineSubmitStrategy submitStrategy = getSubmitStrategy(queue); + final TbRuleEngineProcessingStrategy ackStrategy = getProcessingStrategy(queue); + submitStrategy.init(msgs); + while (!ctx.isStopped() && !consumer.isStopped()) { + TbMsgPackProcessingContext packCtx = new TbMsgPackProcessingContext(queue.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); + submitStrategy.submitAttempt((id, msg) -> ctx.getSubmitExecutor().submit(() -> submitMessage(configuration, stats, packCtx, id, msg))); + + final boolean timeout = !packCtx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); + + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, packCtx); + if (timeout) { + printFirstOrAll(configuration, packCtx, packCtx.getPendingMap(), "Timeout"); + } + if (!packCtx.getFailedMap().isEmpty()) { + printFirstOrAll(configuration, packCtx, packCtx.getFailedMap(), "Failed"); + } + packCtx.printProfilerStats(); + + TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); + if (ctx.isStatsEnabled()) { + stats.log(result, decision.isCommit()); + } + + packCtx.cleanup(); + + if (decision.isCommit()) { + submitStrategy.stop(); + break; + } else { + submitStrategy.update(decision.getReprocessMap()); + } + } + consumer.commit(); + } catch (Exception e) { + if (!ctx.stopped) { + log.warn("Failed to process messages from queue.", e); + try { + Thread.sleep(ctx.getPollDuration()); + } catch (InterruptedException e2) { + log.trace("Failed to wait until the server has capacity to handle new requests", e2); + } + } + } + } + //TODO: refactor and move to the "doDelete" method. Use separate consumer if needed (it is still synchronous). + if (consumer.isQueueDeleted()) { + processQueueDeletion(configuration, consumer); + } + log.info("TB Rule Engine Consumer stopped."); + } + + private void processQueueDeletion(Queue queue, TbQueueConsumer> consumer) { +// long finishTs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(topicDeletionDelayInSec); +// try { +// int n = 0; +// while (System.currentTimeMillis() <= finishTs) { +// List> msgs = consumer.poll(queue.getPollInterval()); +// if (msgs.isEmpty()) { +// continue; +// } +// for (TbProtoQueueMsg msg : msgs) { +// try { +// MsgProtos.TbMsgProto tbMsgProto = MsgProtos.TbMsgProto.parseFrom(msg.getValue().getTbMsg().toByteArray()); +// EntityId originator = EntityIdFactory.getByTypeAndUuid(tbMsgProto.getEntityType(), new UUID(tbMsgProto.getEntityIdMSB(), tbMsgProto.getEntityIdLSB())); +// +// TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, queue.getName(), TenantId.SYS_TENANT_ID, originator); +// producerProvider.getRuleEngineMsgProducer().send(tpi, msg, null); +// n++; +// } catch (Throwable e) { +// log.debug("Failed to move message to system {}: {}", consumer.getTopic(), msg, e); +// } +// } +// consumer.commit(); +// } +// if (n > 0) { +// log.info("Moved {} messages from {} to system {}", n, consumer.getFullTopicNames(), consumer.getTopic()); +// } +// +// consumer.unsubscribe(); +// for (String topic : consumer.getFullTopicNames()) { +// try { +// queueAdmin.deleteTopic(topic); +// log.info("Deleted topic {}", topic); +// } catch (Exception e) { +// log.error("Failed to delete topic {} after unsubscribing", topic, e); +// } +// } +// } catch (Exception e) { +// log.error("Failed to process deletion of {} ({})", consumer.getTopic(), queue.getTenantId(), e); +// } + } + + TbRuleEngineSubmitStrategy getSubmitStrategy(Queue configuration) { + return ctx.getSubmitStrategyFactory().newInstance(configuration.getName(), configuration.getSubmitStrategy()); + } + + TbRuleEngineProcessingStrategy getProcessingStrategy(Queue configuration) { + return ctx.getProcessingStrategyFactory().newInstance(configuration.getName(), configuration.getProcessingStrategy()); + } + + void submitMessage(Queue configuration, TbRuleEngineConsumerStats stats, TbMsgPackProcessingContext packCtx, UUID id, TbProtoQueueMsg msg) { + log.trace("[{}] Creating callback for topic {} message: {}", id, configuration.getName(), msg.getValue()); + TransportProtos.ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); + TenantId tenantId = TenantId.fromUUID(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB())); + TbMsgCallback callback = ctx.prometheusStatsEnabled ? + new TbMsgPackCallback(id, tenantId, packCtx, stats.getTimer(tenantId, SUCCESSFUL_STATUS), stats.getTimer(tenantId, FAILED_STATUS)) : + new TbMsgPackCallback(id, tenantId, packCtx); + try { + if (!toRuleEngineMsg.getTbMsg().isEmpty()) { + forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); + } else { + callback.onSuccess(); + } + } catch (Exception e) { + callback.onFailure(new RuleEngineException(e.getMessage(), e)); + } + } + + private void forwardToRuleEngineActor(String queueName, TenantId tenantId, TransportProtos.ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { + TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback); + QueueToRuleEngineMsg msg; + ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); + Set relationTypes; + if (relationTypesList.size() == 1) { + relationTypes = Collections.singleton(relationTypesList.get(0)); + } else { + relationTypes = new HashSet<>(relationTypesList); + } + msg = new QueueToRuleEngineMsg(tenantId, tbMsg, relationTypes, toRuleEngineMsg.getFailureMessage()); + ctx.getActorContext().tell(msg); + } + + + private void printFirstOrAll(Queue configuration, TbMsgPackProcessingContext ctx, Map> map, String prefix) { + boolean printAll = log.isTraceEnabled(); + log.info("{} to process [{}] messages", prefix, map.size()); + for (Map.Entry> pending : map.entrySet()) { + TransportProtos.ToRuleEngineMsg tmp = pending.getValue().getValue(); + 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: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); + } else { + log.info("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); + break; + } + } + } + + public void printStats(long ts) { + stats.printStats(); + ctx.getStatisticsService().reportQueueStats(ts, stats); + stats.reset(); + } +} diff --git a/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java index 1f41c48f43..9eaca3ca47 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java +++ b/common/util/src/main/java/org/thingsboard/common/util/ThingsBoardThreadFactory.java @@ -22,6 +22,7 @@ import java.util.concurrent.atomic.AtomicInteger; * Copy of Executors.DefaultThreadFactory but with ability to set name of the pool */ public class ThingsBoardThreadFactory implements ThreadFactory { + public static final String THREAD_TOPIC_SEPARATOR = " | "; private static final AtomicInteger poolNumber = new AtomicInteger(1); private final ThreadGroup group; private final AtomicInteger threadNumber = new AtomicInteger(1); @@ -40,6 +41,17 @@ public class ThingsBoardThreadFactory implements ThreadFactory { "-thread-"; } + public static void updateCurrentThreadName(String threadSuffix) { + String name = Thread.currentThread().getName(); + int spliteratorIndex = name.indexOf(THREAD_TOPIC_SEPARATOR); + if (spliteratorIndex > 0) { + name = name.substring(0, spliteratorIndex); + } + name = name + THREAD_TOPIC_SEPARATOR + threadSuffix; + Thread.currentThread().setName(name); + } + + @Override public Thread newThread(Runnable r) { Thread t = new Thread(group, r, From c56132d6e89d00043b0d644850891663ef0b9122 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Tue, 3 Oct 2023 15:04:41 +0300 Subject: [PATCH 209/267] Minor todos --- .../server/service/queue/ruleengine/TbQueueConsumerTask.java | 1 + .../service/queue/ruleengine/TbRuleEngineConsumerContext.java | 3 +++ 2 files changed, 4 insertions(+) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java index 3f549b273c..ed1f36074f 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java @@ -49,6 +49,7 @@ public class TbQueueConsumerTask { public boolean await() { if (task != null) { + //TODO: maybe task.cancel() to interrupt the consumer? try { this.task.get(3, TimeUnit.MINUTES); } catch (ExecutionException | InterruptedException | TimeoutException e) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java index 49f1ad1fab..07307a3f10 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -42,6 +42,7 @@ public class TbRuleEngineConsumerContext { @Value("${queue.rule-engine.topic-deletion-delay:30}") private int topicDeletionDelayInSec; + //TODO: check if they are set correctly. protected volatile boolean stopped = false; protected volatile boolean isReady = false; @@ -59,6 +60,7 @@ public class TbRuleEngineConsumerContext { //TODO: add reasonable limit for mgmt pool. private final ExecutorService mgmtExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-mgmt")); private final ExecutorService consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); + //TODO: do we actually need this? private final ExecutorService submitExecutor = Executors.newSingleThreadExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-submit")); private final ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-scheduler")); @@ -68,6 +70,7 @@ public class TbRuleEngineConsumerContext { @PreDestroy public void stop() { + mgmtExecutor.shutdownNow(); consumersExecutor.shutdownNow(); // TODO: shutdown or shutdownNow? submitExecutor.shutdownNow(); scheduler.shutdownNow(); From 92e0c65a3740f179a9ec651a392fdcfbbfa6f175 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Sat, 14 Oct 2023 21:50:40 +0300 Subject: [PATCH 210/267] Minor refactoring --- .../queue/DefaultTbCoreConsumerService.java | 10 +++- .../DefaultTbRuleEngineConsumerService.java | 59 +++++++++++++------ .../queue/TbRuleEngineConsumerStats.java | 6 +- .../processing/AbstractConsumerService.java | 11 +--- .../TbRuleEngineConsumerContext.java | 45 +++++++------- .../src/main/resources/thingsboard.yml | 4 +- .../controller/BaseQueueControllerTest.java | 6 +- 7 files changed, 85 insertions(+), 56 deletions(-) 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 fd5a252cc5..b2d7700441 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 @@ -142,8 +142,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> usageStatsConsumer; private final TbQueueConsumer> firmwareStatesConsumer; + protected volatile ExecutorService consumersExecutor; protected volatile ExecutorService usageStatsExecutor; - private volatile ExecutorService firmwareStatesExecutor; public DefaultTbCoreConsumerService(TbCoreQueueFactory tbCoreQueueFactory, @@ -186,7 +186,8 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService implements TbRuleEngineConsumerService { private final TbRuleEngineConsumerContext ctx; + private final QueueService queueService; private final TbRuleEngineDeviceRpcService tbDeviceRpcService; private final ConcurrentMap consumers = new ConcurrentHashMap<>(); @@ -68,6 +72,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< ActorSystemContext actorContext, DataDecodingEncodingService encodingService, TbRuleEngineDeviceRpcService tbDeviceRpcService, + QueueService queueService, TbDeviceProfileCache deviceProfileCache, TbAssetProfileCache assetProfileCache, TbTenantProfileCache tenantProfileCache, @@ -77,12 +82,13 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< eventPublisher, tbRuleEngineQueueFactory.createToRuleEngineNotificationsMsgConsumer(), Optional.empty()); this.ctx = ctx; this.tbDeviceRpcService = tbDeviceRpcService; + this.queueService = queueService; } @PostConstruct public void init() { - super.init("tb-rule-engine-notifications-consumer"); // TODO: restore init of the main consumer? - List queues = ctx.findAllQueues(); + super.init("tb-rule-engine-notifications-consumer"); + List queues = queueService.findAllQueues(); for (Queue configuration : queues) { if (partitionService.isManagedByCurrentService(configuration.getTenantId())) { initConsumer(configuration); @@ -91,30 +97,38 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } private void initConsumer(Queue configuration) { - consumers.computeIfAbsent(new QueueKey(ServiceType.TB_RULE_ENGINE, configuration), - key -> new TbRuleEngineQueueConsumerManager(ctx, key)).init(configuration); + getOrCreateConsumer(new QueueKey(ServiceType.TB_RULE_ENGINE, configuration)).init(configuration); } @Override protected void onTbApplicationEvent(PartitionChangeEvent event) { if (event.getServiceType().equals(getServiceType())) { - var consumer = consumers.get(event.getQueueKey()); - if (consumer != null) { - consumer.subscribe(event); - } else { - log.warn("Received invalid partition change event for {} that is not managed by this service", event.getQueueKey()); - } + event.getPartitionsMap().forEach((queueKey, partitions) -> { + var consumer = consumers.get(queueKey); + if (consumer != null) { + consumer.update(partitions); + } else { + log.warn("Received invalid partition change event for {} that is not managed by this service", queueKey); + } + }); } } + @AfterStartUp(order = AfterStartUp.REGULAR_SERVICE) + public void onApplicationEvent(ApplicationReadyEvent event) { + super.onApplicationEvent(event); + ctx.setReady(true); + } + @Override protected void launchMainConsumers() { consumers.values().forEach(TbRuleEngineQueueConsumerManager::launchMainConsumer); } @Override - protected void stopMainConsumers() { + protected void stopConsumers() { consumers.values().forEach(TbRuleEngineQueueConsumerManager::stop); + ctx.stop(); } @Override @@ -164,8 +178,15 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< QueueId queueId = new QueueId(new UUID(queueUpdateMsg.getQueueIdMSB(), queueUpdateMsg.getQueueIdLSB())); String queueName = queueUpdateMsg.getQueueName(); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueName, tenantId); - Queue queue = ctx.getQueueService().findQueueById(tenantId, queueId); - consumers.computeIfAbsent(queueKey, key -> new TbRuleEngineQueueConsumerManager(ctx, key)).update(queue); + Queue queue = queueService.findQueueById(tenantId, queueId); + + TbRuleEngineQueueConsumerManager consumerManager = getOrCreateConsumer(queueKey); + Queue oldQueue = consumerManager.getQueue(); + consumerManager.update(queue); + + if (oldQueue != null && queue.getPartitions() == oldQueue.getPartitions()) { + return; + } } partitionService.updateQueue(queueUpdateMsg); @@ -177,15 +198,19 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< log.info("Received queue delete msg: [{}]", queueDeleteMsg); TenantId tenantId = new TenantId(new UUID(queueDeleteMsg.getTenantIdMSB(), queueDeleteMsg.getTenantIdLSB())); QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queueDeleteMsg.getQueueName(), tenantId); + var consumerManager = consumers.remove(queueKey); + if (consumerManager != null) { + consumerManager.delete(); + } partitionService.removeQueue(queueDeleteMsg); - var manager = consumers.remove(queueKey); - if (manager != null) { - manager.delete(); - } partitionService.recalculatePartitions(ctx.getServiceInfoProvider().getServiceInfo(), new ArrayList<>(partitionService.getOtherServices(ServiceType.TB_RULE_ENGINE))); } + private TbRuleEngineQueueConsumerManager getOrCreateConsumer(QueueKey queueKey) { + return consumers.computeIfAbsent(queueKey, key -> new TbRuleEngineQueueConsumerManager(ctx, key)); + } + @Scheduled(fixedDelayString = "${queue.rule-engine.stats.print-interval-ms}") public void printStats() { if (ctx.isStatsEnabled()) { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java index 45ccbcf32a..842b627c22 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/TbRuleEngineConsumerStats.java @@ -67,9 +67,9 @@ public class TbRuleEngineConsumerStats { private final String queueName; private final TenantId tenantId; - public TbRuleEngineConsumerStats(QueueKey queue, StatsFactory statsFactory) { - this.queueName = queue.getQueueName(); - this.tenantId = queue.getTenantId(); + public TbRuleEngineConsumerStats(QueueKey queueKey, StatsFactory statsFactory) { + this.queueName = queueKey.getQueueName(); + this.tenantId = queueKey.getTenantId(); this.statsFactory = statsFactory; String statsKey = StatsType.RULE_ENGINE.getName() + "." + queueName; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java index b59086a350..d5be1243b7 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/processing/AbstractConsumerService.java @@ -65,7 +65,6 @@ import java.util.stream.Collectors; @Slf4j public abstract class AbstractConsumerService extends TbApplicationEventListener { - protected volatile ExecutorService consumersExecutor; protected volatile ExecutorService notificationsConsumerExecutor; protected volatile boolean stopped = false; protected volatile boolean isReady = false; @@ -99,8 +98,7 @@ public abstract class AbstractConsumerService findAllQueues() { - return queueService.findAllQueues(); + @PostConstruct + public void init() { + this.consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); + this.mgmtExecutor = Executors.newFixedThreadPool(mgmtThreadPoolSize, ThingsBoardThreadFactory.forName("tb-rule-engine-mgmt")); + this.scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-scheduler")); } - @PreDestroy public void stop() { - mgmtExecutor.shutdownNow(); - consumersExecutor.shutdownNow(); // TODO: shutdown or shutdownNow? - submitExecutor.shutdownNow(); scheduler.shutdownNow(); + consumersExecutor.shutdown(); + mgmtExecutor.shutdown(); + try { + mgmtExecutor.awaitTermination(15, TimeUnit.SECONDS); + } catch (InterruptedException e) { + log.warn("Failed to await mgmtExecutor termination"); + } } } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 9fbfd2fc63..6f51413ccd 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1303,7 +1303,9 @@ queue: 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. # After a queue is deleted (or profile's isolation option was disabled), Rule Engine will continue reading related topics during this period, before deleting the actual topics - topic-deletion-delay: "${TB_QUEUE_RULE_ENGINE_TOPIC_DELETION_DELAY_SEC:30}" + topic-deletion-delay: "${TB_QUEUE_RULE_ENGINE_TOPIC_DELETION_DELAY_SEC:15}" + # Size of the thread pool that handles management operations such as subscribe, unsubscribe, queue delete, etc. + management-thread-pool-size: "${TB_QUEUE_RULE_ENGINE_MGMT_THREAD_POOL_SIZE:12}" transport: # For high priority notifications that require minimum latency and processing time notifications_topic: "${TB_QUEUE_TRANSPORT_NOTIFICATIONS_TOPIC:tb_transport.notifications}" diff --git a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java index 845ac49f15..8418ba67d9 100644 --- a/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/BaseQueueControllerTest.java @@ -37,12 +37,14 @@ import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.queue.SubmitStrategy; import org.thingsboard.server.common.data.queue.SubmitStrategyType; import org.thingsboard.server.common.msg.queue.RuleEngineException; +import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.stats.StatsFactory; import org.thingsboard.server.dao.asset.AssetService; import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.dao.timeseries.TimeseriesDao; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.QueueKey; import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingResult; import org.thingsboard.server.service.stats.DefaultRuleEngineStatisticsService; @@ -163,7 +165,7 @@ public class BaseQueueControllerTest extends AbstractControllerTest { tenantId, ruleEngineException ))); - TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(queue, statsFactory); + TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(new QueueKey(ServiceType.TB_RULE_ENGINE, queue), statsFactory); testStats.log(testProcessingResult, true); int queueStatsTtlDays = 14; @@ -215,7 +217,7 @@ public class BaseQueueControllerTest extends AbstractControllerTest { tenantId, ruleEngineException ))); - TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(queue, statsFactory); + TbRuleEngineConsumerStats testStats = new TbRuleEngineConsumerStats(new QueueKey(ServiceType.TB_RULE_ENGINE, queue), statsFactory); testStats.log(testProcessingResult, true); ruleEngineStatisticsService.reportQueueStats(System.currentTimeMillis(), testStats); From cf951ee2b22cde58b6fcd39a0f91d13213ce8b25 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 17 Oct 2023 11:23:58 +0300 Subject: [PATCH 211/267] Multiple improvements for Rule Engine consumer services --- .../DefaultTbRuleEngineConsumerService.java | 6 +- .../service/queue/ruleengine/QueueEvent.java | 17 +- .../TbQueueConsumerManagerTask.java | 25 +- .../queue/ruleengine/TbQueueConsumerTask.java | 43 +- .../TbRuleEngineConsumerContext.java | 19 +- .../TbRuleEngineQueueConsumerManager.java | 519 ++++++++++-------- .../server/queue/TbQueueConsumer.java | 6 +- .../AbstractTbQueueConsumerTemplate.java | 39 +- .../queue/kafka/TbKafkaConsumerTemplate.java | 1 - .../queue/memory/InMemoryTbQueueConsumer.java | 17 +- 10 files changed, 384 insertions(+), 308 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 164b48c25f..64139530b1 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.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, @@ -121,9 +121,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< } @Override - protected void launchMainConsumers() { - consumers.values().forEach(TbRuleEngineQueueConsumerManager::launchMainConsumer); - } + protected void launchMainConsumers() {} @Override protected void stopConsumers() { diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java index 4d01d15d9a..a4a3bcc59a 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java @@ -1,9 +1,24 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; import java.io.Serializable; public enum QueueEvent implements Serializable { - CREATED, LAUNCHED, UPDATED, PARTITION_CHANGE, STOP, DELETED + PARTITION_CHANGE, CONFIG_UPDATE, STOP, DELETE } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java index 5b4f164a10..6f1adbdcf2 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerManagerTask.java @@ -15,18 +15,33 @@ */ package org.thingsboard.server.service.queue.ruleengine; -import lombok.Data; -import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; +import lombok.Getter; +import lombok.ToString; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import java.util.Set; -@Data +@Getter +@ToString public class TbQueueConsumerManagerTask { private final QueueEvent event; - private final Queue queue; - private final Set partitions; + private Queue queue; + private Set partitions; + + public TbQueueConsumerManagerTask(QueueEvent event) { + this.event = event; + } + + public TbQueueConsumerManagerTask(QueueEvent event, Queue queue) { + this.event = event; + this.queue = queue; + } + + public TbQueueConsumerManagerTask(QueueEvent event, Set partitions) { + this.event = event; + this.partitions = partitions; + } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java index ed1f36074f..a0a5579951 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.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, @@ -21,51 +21,44 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; -import org.thingsboard.server.queue.discovery.QueueKey; import java.util.Set; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; @Data @Slf4j public class TbQueueConsumerTask { - private final QueueKey key; - private final Object id; + private final Object key; private final TbQueueConsumer> consumer; private volatile Future task; - public void stop() { - this.consumer.stop(); + public void subscribe(Set partitions) { + log.trace("[{}] Subscribing to partitions: {}", key, partitions); + consumer.subscribe(partitions); } - public boolean stopAndAwait() { - this.consumer.stop(); - return await(); + public void initiateStop() { + log.debug("[{}] Initiating stop", key); + consumer.stop(); } - public boolean await() { - if (task != null) { - //TODO: maybe task.cancel() to interrupt the consumer? + public void awaitFinish() { + log.trace("[{}] Awaiting finish", key); + if (isRunning()) { try { - this.task.get(3, TimeUnit.MINUTES); - } catch (ExecutionException | InterruptedException | TimeoutException e) { - log.warn("[{}][{}] Failed to await for consumer to stop", key, id, e); - return false; + task.get(60, TimeUnit.SECONDS); + task = null; + } catch (Exception e) { + log.warn("[{}] Failed to await for consumer to stop", key, e); } } - return true; + log.trace("[{}] Awaited finish", key); } - public void subscribe(Set partitions) { - this.consumer.subscribe(partitions); + public boolean isRunning() { + return task != null && !task.isDone(); } - - public void unsubscribe() { - this.consumer.unsubscribe(); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java index c1d17746e1..325a685972 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -1,3 +1,18 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; import lombok.Data; @@ -36,8 +51,8 @@ public class TbRuleEngineConsumerContext { @Value("${queue.rule-engine.stats.enabled:true}") private boolean statsEnabled; @Value("${queue.rule-engine.prometheus-stats.enabled:false}") - boolean prometheusStatsEnabled; - @Value("${queue.rule-engine.topic-deletion-delay:30}") + private boolean prometheusStatsEnabled; + @Value("${queue.rule-engine.topic-deletion-delay:15}") private int topicDeletionDelayInSec; @Value("${queue.rule-engine.management-thread-pool-size:12}") private int mgmtThreadPoolSize; diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java index 2599a214f0..dc3966d0d2 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.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, @@ -16,8 +16,7 @@ package org.thingsboard.server.service.queue.ruleengine; import com.google.protobuf.ProtocolStringList; -import lombok.Data; -import lombok.SneakyThrows; +import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.common.data.id.EntityId; @@ -32,11 +31,10 @@ import org.thingsboard.server.common.msg.queue.RuleNodeInfo; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbMsgCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; -import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.QueueKey; -import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; import org.thingsboard.server.service.queue.TbMsgPackCallback; import org.thingsboard.server.service.queue.TbMsgPackProcessingContext; import org.thingsboard.server.service.queue.TbRuleEngineConsumerStats; @@ -45,19 +43,20 @@ import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingRes import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategy; import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategy; +import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; +import java.util.stream.Collectors; -@Data @Slf4j public class TbRuleEngineQueueConsumerManager { @@ -65,87 +64,83 @@ public class TbRuleEngineQueueConsumerManager { public static final String FAILED_STATUS = "failed"; private final TbRuleEngineConsumerContext ctx; - private final QueueKey key; - - private final ReentrantLock lock = new ReentrantLock(); //NonfairSync - private final ConcurrentMap consumersPerPartition = new ConcurrentHashMap<>(); + private final QueueKey queueKey; private final TbRuleEngineConsumerStats stats; + private final ReentrantLock lock = new ReentrantLock(); //NonfairSync - private volatile Set partitions = Collections.emptySet(); + @Getter private volatile Queue queue; - private volatile TbQueueConsumerTask mainConsumer; + @Getter + private volatile Set partitions; + private volatile ConsumerWrapper consumerWrapper; + + private volatile boolean stopped; private final java.util.Queue tasks = new ConcurrentLinkedQueue<>(); - public TbRuleEngineQueueConsumerManager(TbRuleEngineConsumerContext ctx, QueueKey key) { + public TbRuleEngineQueueConsumerManager(TbRuleEngineConsumerContext ctx, QueueKey queueKey) { this.ctx = ctx; - this.key = key; - this.stats = new TbRuleEngineConsumerStats(key, ctx.getStatsFactory()); + this.queueKey = queueKey; + this.stats = new TbRuleEngineConsumerStats(queueKey, ctx.getStatsFactory()); } public void init(Queue queue) { - processTask(new TbQueueConsumerManagerTask(QueueEvent.CREATED, queue, null)); + doInit(queue); } public void update(Queue queue) { - processTask(new TbQueueConsumerManagerTask(QueueEvent.UPDATED, queue, null)); + addTask(new TbQueueConsumerManagerTask(QueueEvent.CONFIG_UPDATE, queue)); } - public void subscribe(PartitionChangeEvent event) { - processTask(new TbQueueConsumerManagerTask(QueueEvent.PARTITION_CHANGE, queue, event.getPartitions())); - } - - public void launchMainConsumer() { - processTask(new TbQueueConsumerManagerTask(QueueEvent.LAUNCHED, null, null)); + public void update(Set partitions) { + addTask(new TbQueueConsumerManagerTask(QueueEvent.PARTITION_CHANGE, partitions)); } public void stop() { - processTask(new TbQueueConsumerManagerTask(QueueEvent.STOP, null, null)); + addTask(new TbQueueConsumerManagerTask(QueueEvent.STOP)); } public void delete() { - processTask(new TbQueueConsumerManagerTask(QueueEvent.DELETED, null, null)); + addTask(new TbQueueConsumerManagerTask(QueueEvent.DELETE)); } - private void processTask(TbQueueConsumerManagerTask todo) { + private void addTask(TbQueueConsumerManagerTask todo) { + if (stopped) { + return; + } tasks.add(todo); - log.info("[{}] Adding task: {}", key, todo); + log.trace("[{}] Added task: {}", queueKey, todo); tryProcessTasks(); } private void tryProcessTasks() { + if (!ctx.isReady()) { + log.debug("[{}] TbRuleEngineConsumerContext is not ready yet, will process tasks later", queueKey); + ctx.getScheduler().schedule(this::tryProcessTasks, 1, TimeUnit.SECONDS); + return; + } ctx.getMgmtExecutor().submit(() -> { if (lock.tryLock()) { try { Queue newConfiguration = null; Set newPartitions = null; - while (!tasks.isEmpty()) { + while (!stopped) { TbQueueConsumerManagerTask task = tasks.poll(); - switch (task.getEvent()) { - case CREATED: - doInit(task.getQueue()); - break; - case LAUNCHED: - if (!queue.isConsumerPerPartition()) { - doLaunchMainConsumer(); - } - break; - case UPDATED: - newConfiguration = task.getQueue(); - break; - case PARTITION_CHANGE: - newPartitions = task.getPartitions(); - break; - case STOP: - newConfiguration = null; - newPartitions = null; - doStop(); - break; - case DELETED: - newConfiguration = null; - newPartitions = null; - doDelete(); - break; + if (task == null) { + break; + } + log.trace("[{}] Processing task: {}", queueKey, task); + + if (task.getEvent() == QueueEvent.PARTITION_CHANGE) { + newPartitions = task.getPartitions(); + } else if (task.getEvent() == QueueEvent.CONFIG_UPDATE) { + newConfiguration = task.getQueue(); + } else if (task.getEvent() == QueueEvent.STOP) { + doStop(); + return; + } else if (task.getEvent() == QueueEvent.DELETE) { + doDelete(); + return; } } if (newConfiguration != null) { @@ -158,158 +153,108 @@ public class TbRuleEngineQueueConsumerManager { lock.unlock(); } } else { - log.debug("[{}] Failed to acquire lock.", key); + log.trace("[{}] Failed to acquire lock", queueKey); ctx.getScheduler().schedule(this::tryProcessTasks, 1, TimeUnit.SECONDS); } }); } - public void doInit(Queue queue) { - log.info("[{}] Init consumer with queue: {}", key, queue); + private void doInit(Queue queue) { this.queue = queue; if (queue.isConsumerPerPartition()) { - log.debug("[{}] Ignore init event since isConsumerPerPartition is enabled.", key); + consumerWrapper = new ConsumerPerPartitionWrapper(); } else { - mainConsumer = new TbQueueConsumerTask(key, "main", ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); - } - } - - private void doLaunchMainConsumer() { - if (mainConsumer != null) { - launchConsumer(mainConsumer, queue, mainConsumer.getId(), queue.getName()); - } else { - log.warn("[{}] Can't launch main consumer since it is empty!", key); + consumerWrapper = new SingleConsumerWrapper(); } + log.debug("[{}] Initialized consumer for queue: {}", queueKey, queue); } private void doUpdate(Queue newQueue) { - log.info("[{}] Processing queue update: {}", key, newQueue); - var oldQueue = queue; + log.info("[{}] Processing queue update: {}", queueKey, newQueue); + var oldQueue = this.queue; + this.queue = newQueue; if (log.isTraceEnabled()) { - log.trace("[{}] Old queue configuration: {}", key, oldQueue); - log.trace("[{}] New queue configuration: {}", key, newQueue); - } - if (oldQueue != null) { - doStop(oldQueue); - } - doInit(newQueue); - if (!newQueue.isConsumerPerPartition()) { - doLaunchMainConsumer(); + log.trace("[{}] Old queue configuration: {}", queueKey, oldQueue); + log.trace("[{}] New queue configuration: {}", queueKey, newQueue); } - } - - private void doUpdate(Set partitions) { - log.info("[{}] Subscribing to partitions: {}", key, partitions); - if (queue.isConsumerPerPartition()) { - log.debug("[{}] Subscribing consumers per partition separately: {}", key, partitions); - Set addedPartitions = new HashSet<>(partitions); - addedPartitions.removeAll(consumersPerPartition.keySet()); - log.info("calculated addedPartitions {}", addedPartitions); - - Set removedPartitions = new HashSet<>(consumersPerPartition.keySet()); - removedPartitions.removeAll(partitions); - log.info("calculated removedPartitions {}", removedPartitions); - removedPartitions.forEach((tpi) -> { - log.info("[{}] Unsubscribing from topic: {}", queue, tpi); - consumersPerPartition.get(tpi).unsubscribe(); - }); + if (oldQueue == null) { + doInit(queue); + } else if (newQueue.isConsumerPerPartition() != oldQueue.isConsumerPerPartition()) { + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::initiateStop); + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); - removedPartitions.forEach((tpi) -> { - log.info("[{}] Removing consumer for topic: {}", queue, tpi); - consumersPerPartition.get(tpi).stopAndAwait(); - consumersPerPartition.remove(tpi); - }); - - addedPartitions.forEach((tpi) -> { - log.info("[{}] Adding consumer for topic: {}", key, tpi); - TbQueueConsumerTask consumerTask = new TbQueueConsumerTask(key, tpi, ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); - consumersPerPartition.put(tpi, consumerTask); - //TODO: Is it ok to subscribe first? - consumerTask.subscribe(Collections.singleton(tpi)); - launchConsumer(consumerTask, queue, mainConsumer.getId(), key + "-" + tpi.getPartition().orElse(-999999)); - }); + doInit(queue); + if (partitions != null) { + doUpdate(partitions); // even if partitions number was changed, there can be no partition change event + } } else { - mainConsumer.subscribe(partitions); + // do nothing, because partitions change (if they changed) will be handled on PartitionChangeEvent, + // and changes to pollInterval/packProcessingTimeout/submitStrategy/processingStrategy will be picked up by consumer on the fly, + // and queue topic and name are immutable } } - private void doStop() { - doStop(queue); + private void doUpdate(Set partitions) { + this.partitions = partitions; + consumerWrapper.updatePartitions(partitions); } - private void doStop(Queue queue) { - if (queue.isConsumerPerPartition()) { - consumersPerPartition.values().forEach(TbQueueConsumerTask::unsubscribe); - consumersPerPartition.values().forEach(TbQueueConsumerTask::stopAndAwait); - } else if (mainConsumer != null) { - mainConsumer.unsubscribe(); - mainConsumer.stopAndAwait(); - } + private void doStop() { + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::initiateStop); + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); + log.debug("[{}] Unsubscribed and stopped consumers", queueKey); + stopped = true; } private void doDelete() { - doStop(); - //TODO: repack messages + stopped = true; + log.info("[{}] Handling queue deletion", queueKey); + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); + + List>> queueConsumers = consumerWrapper.getConsumers().stream() + .map(TbQueueConsumerTask::getConsumer).collect(Collectors.toList()); + ctx.getConsumersExecutor().submit(() -> { + drainQueue(queueConsumers); + + queueConsumers.forEach(consumer -> { + for (String topic : consumer.getFullTopicNames()) { + try { + ctx.getQueueAdmin().deleteTopic(topic); + log.info("Deleted topic {}", topic); + } catch (Exception e) { + log.error("Failed to delete topic {}", topic, e); + } + } + try { + consumer.unsubscribe(); + } catch (Exception e) { + log.error("[{}] Failed to unsubscribe consumer", queueKey, e); + } + }); + }); } - @SneakyThrows - void launchConsumer(TbQueueConsumerTask consumerTask, Queue configuration, Object consumerKey, String threadSuffix) { - log.info("[{}] Launching consumer: [{}]", key, consumerKey); - while (!ctx.isReady) { - //TODO: Remember this task. Cancel previous task if needed. - log.debug("[{}][{}] Waiting for consumer to get ready..", key, consumerKey); - Thread.sleep(1000); - } - consumerTask.setTask(ctx.getConsumersExecutor().submit(() -> consumerLoop(consumerTask.getConsumer(), configuration, threadSuffix))); + private void launchConsumer(TbQueueConsumerTask consumerTask) { + log.info("[{}] Launching consumer", consumerTask.getKey()); + Future consumerLoop = ctx.getConsumersExecutor().submit(() -> { + ThingsBoardThreadFactory.updateCurrentThreadName(consumerTask.getKey().toString()); + consumerLoop(consumerTask.getConsumer()); + }); + consumerTask.setTask(consumerLoop); } - void consumerLoop(TbQueueConsumer> consumer, Queue configuration, String threadSuffix) { - ThingsBoardThreadFactory.updateCurrentThreadName(threadSuffix); - while (!ctx.stopped && !consumer.isStopped() - //TODO: remove this. - && !consumer.isQueueDeleted()) { + private void consumerLoop(TbQueueConsumer> consumer) { + while (!stopped && !consumer.isStopped()) { try { - List> msgs = consumer.poll(queue.getPollInterval()); + List> msgs = consumer.poll(queue.getPollInterval()); if (msgs.isEmpty()) { continue; } - final TbRuleEngineSubmitStrategy submitStrategy = getSubmitStrategy(queue); - final TbRuleEngineProcessingStrategy ackStrategy = getProcessingStrategy(queue); - submitStrategy.init(msgs); - while (!ctx.isStopped() && !consumer.isStopped()) { - TbMsgPackProcessingContext packCtx = new TbMsgPackProcessingContext(queue.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); - submitStrategy.submitAttempt((id, msg) -> ctx.getSubmitExecutor().submit(() -> submitMessage(configuration, stats, packCtx, id, msg))); - - final boolean timeout = !packCtx.await(configuration.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); - - TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(configuration.getName(), timeout, packCtx); - if (timeout) { - printFirstOrAll(configuration, packCtx, packCtx.getPendingMap(), "Timeout"); - } - if (!packCtx.getFailedMap().isEmpty()) { - printFirstOrAll(configuration, packCtx, packCtx.getFailedMap(), "Failed"); - } - packCtx.printProfilerStats(); - - TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); - if (ctx.isStatsEnabled()) { - stats.log(result, decision.isCommit()); - } - - packCtx.cleanup(); - - if (decision.isCommit()) { - submitStrategy.stop(); - break; - } else { - submitStrategy.update(decision.getReprocessMap()); - } - } - consumer.commit(); + processMsgs(msgs, consumer, queue); } catch (Exception e) { - if (!ctx.stopped) { - log.warn("Failed to process messages from queue.", e); + if (!stopped) { + log.warn("Failed to process messages from queue", e); try { Thread.sleep(ctx.getPollDuration()); } catch (InterruptedException e2) { @@ -318,72 +263,68 @@ public class TbRuleEngineQueueConsumerManager { } } } - //TODO: refactor and move to the "doDelete" method. Use separate consumer if needed (it is still synchronous). - if (consumer.isQueueDeleted()) { - processQueueDeletion(configuration, consumer); + if (consumer.isStopped()) { + consumer.unsubscribe(); } - log.info("TB Rule Engine Consumer stopped."); + log.info("Rule Engine consumer stopped"); } - private void processQueueDeletion(Queue queue, TbQueueConsumer> consumer) { -// long finishTs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(topicDeletionDelayInSec); -// try { -// int n = 0; -// while (System.currentTimeMillis() <= finishTs) { -// List> msgs = consumer.poll(queue.getPollInterval()); -// if (msgs.isEmpty()) { -// continue; -// } -// for (TbProtoQueueMsg msg : msgs) { -// try { -// MsgProtos.TbMsgProto tbMsgProto = MsgProtos.TbMsgProto.parseFrom(msg.getValue().getTbMsg().toByteArray()); -// EntityId originator = EntityIdFactory.getByTypeAndUuid(tbMsgProto.getEntityType(), new UUID(tbMsgProto.getEntityIdMSB(), tbMsgProto.getEntityIdLSB())); -// -// TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, queue.getName(), TenantId.SYS_TENANT_ID, originator); -// producerProvider.getRuleEngineMsgProducer().send(tpi, msg, null); -// n++; -// } catch (Throwable e) { -// log.debug("Failed to move message to system {}: {}", consumer.getTopic(), msg, e); -// } -// } -// consumer.commit(); -// } -// if (n > 0) { -// log.info("Moved {} messages from {} to system {}", n, consumer.getFullTopicNames(), consumer.getTopic()); -// } -// -// consumer.unsubscribe(); -// for (String topic : consumer.getFullTopicNames()) { -// try { -// queueAdmin.deleteTopic(topic); -// log.info("Deleted topic {}", topic); -// } catch (Exception e) { -// log.error("Failed to delete topic {} after unsubscribing", topic, e); -// } -// } -// } catch (Exception e) { -// log.error("Failed to process deletion of {} ({})", consumer.getTopic(), queue.getTenantId(), e); -// } + private void processMsgs(List> msgs, + TbQueueConsumer> consumer, + Queue queue) throws InterruptedException { + TbRuleEngineSubmitStrategy submitStrategy = getSubmitStrategy(queue); + TbRuleEngineProcessingStrategy ackStrategy = getProcessingStrategy(queue); + submitStrategy.init(msgs); + while (!stopped && !consumer.isStopped()) { + TbMsgPackProcessingContext packCtx = new TbMsgPackProcessingContext(queue.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); + submitStrategy.submitAttempt((id, msg) -> submitMessage(packCtx, id, msg)); + + final boolean timeout = !packCtx.await(queue.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); + + TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(queue.getName(), timeout, packCtx); + if (timeout) { + printFirstOrAll(packCtx, packCtx.getPendingMap(), "Timeout"); + } + if (!packCtx.getFailedMap().isEmpty()) { + printFirstOrAll(packCtx, packCtx.getFailedMap(), "Failed"); + } + packCtx.printProfilerStats(); + + TbRuleEngineProcessingDecision decision = ackStrategy.analyze(result); + if (ctx.isStatsEnabled()) { + stats.log(result, decision.isCommit()); + } + + packCtx.cleanup(); + + if (decision.isCommit()) { + submitStrategy.stop(); + consumer.commit(); + break; + } else { + submitStrategy.update(decision.getReprocessMap()); + } + } } - TbRuleEngineSubmitStrategy getSubmitStrategy(Queue configuration) { - return ctx.getSubmitStrategyFactory().newInstance(configuration.getName(), configuration.getSubmitStrategy()); + private TbRuleEngineSubmitStrategy getSubmitStrategy(Queue queue) { + return ctx.getSubmitStrategyFactory().newInstance(queue.getName(), queue.getSubmitStrategy()); } - TbRuleEngineProcessingStrategy getProcessingStrategy(Queue configuration) { - return ctx.getProcessingStrategyFactory().newInstance(configuration.getName(), configuration.getProcessingStrategy()); + private TbRuleEngineProcessingStrategy getProcessingStrategy(Queue queue) { + return ctx.getProcessingStrategyFactory().newInstance(queue.getName(), queue.getProcessingStrategy()); } - void submitMessage(Queue configuration, TbRuleEngineConsumerStats stats, TbMsgPackProcessingContext packCtx, UUID id, TbProtoQueueMsg msg) { - log.trace("[{}] Creating callback for topic {} message: {}", id, configuration.getName(), msg.getValue()); - TransportProtos.ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); + private void submitMessage(TbMsgPackProcessingContext packCtx, UUID id, TbProtoQueueMsg msg) { + log.trace("[{}] Creating callback for topic {} message: {}", id, queue.getName(), msg.getValue()); + ToRuleEngineMsg toRuleEngineMsg = msg.getValue(); TenantId tenantId = TenantId.fromUUID(new UUID(toRuleEngineMsg.getTenantIdMSB(), toRuleEngineMsg.getTenantIdLSB())); - TbMsgCallback callback = ctx.prometheusStatsEnabled ? + TbMsgCallback callback = ctx.isPrometheusStatsEnabled() ? new TbMsgPackCallback(id, tenantId, packCtx, stats.getTimer(tenantId, SUCCESSFUL_STATUS), stats.getTimer(tenantId, FAILED_STATUS)) : new TbMsgPackCallback(id, tenantId, packCtx); try { if (!toRuleEngineMsg.getTbMsg().isEmpty()) { - forwardToRuleEngineActor(configuration.getName(), tenantId, toRuleEngineMsg, callback); + forwardToRuleEngineActor(queue.getName(), tenantId, toRuleEngineMsg, callback); } else { callback.onSuccess(); } @@ -392,7 +333,7 @@ public class TbRuleEngineQueueConsumerManager { } } - private void forwardToRuleEngineActor(String queueName, TenantId tenantId, TransportProtos.ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { + private void forwardToRuleEngineActor(String queueName, TenantId tenantId, ToRuleEngineMsg toRuleEngineMsg, TbMsgCallback callback) { TbMsg tbMsg = TbMsg.fromBytes(queueName, toRuleEngineMsg.getTbMsg().toByteArray(), callback); QueueToRuleEngineMsg msg; ProtocolStringList relationTypesList = toRuleEngineMsg.getRelationTypesList(); @@ -406,16 +347,15 @@ public class TbRuleEngineQueueConsumerManager { ctx.getActorContext().tell(msg); } - - private void printFirstOrAll(Queue configuration, TbMsgPackProcessingContext ctx, Map> map, String prefix) { + private void printFirstOrAll(TbMsgPackProcessingContext ctx, Map> map, String prefix) { boolean printAll = log.isTraceEnabled(); - log.info("{} to process [{}] messages", prefix, map.size()); - for (Map.Entry> pending : map.entrySet()) { - TransportProtos.ToRuleEngineMsg tmp = pending.getValue().getValue(); - TbMsg tmpMsg = TbMsg.fromBytes(configuration.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); + log.info("[{}] {} to process [{}] messages", queueKey, prefix, map.size()); + for (Map.Entry> pending : map.entrySet()) { + ToRuleEngineMsg tmp = pending.getValue().getValue(); + TbMsg tmpMsg = TbMsg.fromBytes(queue.getName(), tmp.getTbMsg().toByteArray(), TbMsgCallback.EMPTY); RuleNodeInfo ruleNodeInfo = ctx.getLastVisitedRuleNode(pending.getKey()); if (printAll) { - log.trace("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); + log.trace("[{}][{}] {} to process message: {}, Last Rule Node: {}", queueKey, TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); } else { log.info("[{}] {} to process message: {}, Last Rule Node: {}", TenantId.fromUUID(new UUID(tmp.getTenantIdMSB(), tmp.getTenantIdLSB())), prefix, tmpMsg, ruleNodeInfo); break; @@ -428,4 +368,117 @@ public class TbRuleEngineQueueConsumerManager { ctx.getStatisticsService().reportQueueStats(ts, stats); stats.reset(); } + + private void drainQueue(List>> consumers) { + long finishTs = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(ctx.getTopicDeletionDelayInSec()); + try { + int n = 0; + while (System.currentTimeMillis() <= finishTs) { + for (TbQueueConsumer> consumer : consumers) { + List> msgs = consumer.poll(queue.getPollInterval()); + if (msgs.isEmpty()) { + continue; + } + for (TbProtoQueueMsg msg : msgs) { + try { + MsgProtos.TbMsgProto tbMsgProto = MsgProtos.TbMsgProto.parseFrom(msg.getValue().getTbMsg().toByteArray()); + EntityId originator = EntityIdFactory.getByTypeAndUuid(tbMsgProto.getEntityType(), new UUID(tbMsgProto.getEntityIdMSB(), tbMsgProto.getEntityIdLSB())); + + TopicPartitionInfo tpi = ctx.getPartitionService().resolve(ServiceType.TB_RULE_ENGINE, queue.getName(), TenantId.SYS_TENANT_ID, originator); + ctx.getProducerProvider().getRuleEngineMsgProducer().send(tpi, msg, null); + n++; + } catch (Throwable e) { + log.warn("Failed to move message to system {}: {}", consumer.getTopic(), msg, e); + } + } + consumer.commit(); + } + } + if (n > 0) { + log.info("Moved {} messages from {} to system {}", n, queueKey, queue.getName()); + } + } catch (Exception e) { + log.error("[{}] Failed to drain queue", queueKey, e); + } + } + + private static String partitionsToString(Collection partitions) { + return partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.joining(", ", "[", "]")); + } + + interface ConsumerWrapper { + + void updatePartitions(Set partitions); + + Collection getConsumers(); + + } + + class ConsumerPerPartitionWrapper implements ConsumerWrapper { + private final Map consumers = new HashMap<>(); + + @Override + public void updatePartitions(Set partitions) { + Set addedPartitions = new HashSet<>(partitions); + addedPartitions.removeAll(consumers.keySet()); + + Set removedPartitions = new HashSet<>(consumers.keySet()); + removedPartitions.removeAll(partitions); + log.info("[{}] Added partitions: {}, removed partitions: {}", queueKey, partitionsToString(addedPartitions), partitionsToString(removedPartitions)); + + removedPartitions.forEach((tpi) -> { + consumers.get(tpi).initiateStop(); + }); + removedPartitions.forEach((tpi) -> { + consumers.remove(tpi).awaitFinish(); + }); + + addedPartitions.forEach((tpi) -> { + String key = queueKey + "-" + tpi.getPartition().orElse(-999999); + TbQueueConsumerTask consumer = new TbQueueConsumerTask(key, ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); + consumers.put(tpi, consumer); + consumer.subscribe(Set.of(tpi)); + launchConsumer(consumer); + }); + } + + @Override + public Collection getConsumers() { + return consumers.values(); + } + } + + class SingleConsumerWrapper implements ConsumerWrapper { + private TbQueueConsumerTask consumer; + + @Override + public void updatePartitions(Set partitions) { + log.info("[{}] New partitions: {}", queueKey, partitionsToString(partitions)); + if (partitions.isEmpty()) { + if (consumer != null && consumer.isRunning()) { + consumer.initiateStop(); + consumer.awaitFinish(); + } + consumer = null; + return; + } + + if (consumer == null) { + consumer = new TbQueueConsumerTask(queueKey, ctx.getQueueFactory().createToRuleEngineMsgConsumer(queue)); + } + consumer.subscribe(partitions); + if (!consumer.isRunning()) { + launchConsumer(consumer); + } + } + + @Override + public Collection getConsumers() { + if (consumer == null) { + return Collections.emptyList(); + } + return List.of(consumer); + } + } + } diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java index 9c41f9d342..21216e164e 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/queue/TbQueueConsumer.java @@ -28,6 +28,8 @@ public interface TbQueueConsumer { void subscribe(Set partitions); + void stop(); + void unsubscribe(); List poll(long durationInMillis); @@ -36,10 +38,6 @@ public interface TbQueueConsumer { boolean isStopped(); - void onQueueDelete(); - - boolean isQueueDeleted(); - List getFullTopicNames(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueConsumerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueConsumerTemplate.java index 2ebe41850d..073371ebb5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueConsumerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/common/AbstractTbQueueConsumerTemplate.java @@ -44,7 +44,6 @@ public abstract class AbstractTbQueueConsumerTemplate i protected volatile Set partitions; protected final ReentrantLock consumerLock = new ReentrantLock(); //NonfairSync final Queue> subscribeQueue = new ConcurrentLinkedQueue<>(); - protected volatile boolean queueDeleted = false; @Getter private final String topic; @@ -55,7 +54,7 @@ public abstract class AbstractTbQueueConsumerTemplate i @Override public void subscribe() { - log.info("enqueue topic subscribe {} ", topic); + log.debug("enqueue topic subscribe {} ", topic); if (stopped) { log.error("trying subscribe, but consumer stopped for topic {}", topic); return; @@ -65,7 +64,7 @@ public abstract class AbstractTbQueueConsumerTemplate i @Override public void subscribe(Set partitions) { - log.info("enqueue topics subscribe {} ", partitions); + log.debug("enqueue topics subscribe {} ", partitions); if (stopped) { log.error("trying subscribe, but consumer stopped for topic {}", topic); return; @@ -78,7 +77,8 @@ public abstract class AbstractTbQueueConsumerTemplate i List records; long startNanos = System.nanoTime(); if (stopped) { - return errorAndReturnEmpty(); + log.error("poll invoked but consumer stopped for topic " + topic, new RuntimeException("stacktrace")); + return emptyList(); } if (!subscribed && partitions == null && subscribeQueue.isEmpty()) { return sleepAndReturnEmpty(startNanos, durationInMillis); @@ -96,6 +96,7 @@ public abstract class AbstractTbQueueConsumerTemplate i } if (!subscribed) { List topicNames = getFullTopicNames(); + log.info("Subscribing to topics {}", topicNames); doSubscribe(topicNames); subscribed = true; } @@ -127,11 +128,6 @@ public abstract class AbstractTbQueueConsumerTemplate i return result; } - List errorAndReturnEmpty() { - log.error("poll invoked but consumer stopped for topic" + topic, new RuntimeException("stacktrace")); - return emptyList(); - } - List sleepAndReturnEmpty(final long startNanos, final long durationInMillis) { long durationNanos = TimeUnit.MILLISECONDS.toNanos(durationInMillis); long spentNanos = System.nanoTime() - startNanos; @@ -163,15 +159,20 @@ public abstract class AbstractTbQueueConsumerTemplate i } } + @Override + public void stop() { + stopped = true; + } + @Override public void unsubscribe() { - log.info("Unsubscribing from topics and stopping consumer for topics {}", partitions.stream() - .map(TopicPartitionInfo::getFullTopicName) - .collect(Collectors.joining(", "))); + log.info("Unsubscribing and stopping consumer for topics {}", getFullTopicNames()); stopped = true; consumerLock.lock(); try { - doUnsubscribe(); + if (subscribed) { + doUnsubscribe(); + } } finally { consumerLock.unlock(); } @@ -192,17 +193,11 @@ public abstract class AbstractTbQueueConsumerTemplate i abstract protected void doUnsubscribe(); - @Override - public void onQueueDelete() { - queueDeleted = true; - } - - public boolean isQueueDeleted() { - return queueDeleted; - } - @Override public List getFullTopicNames() { + if (partitions == null) { + return Collections.emptyList(); + } return partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList()); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerTemplate.java b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerTemplate.java index 9f58446966..ff3f0cc9b3 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerTemplate.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/kafka/TbKafkaConsumerTemplate.java @@ -73,7 +73,6 @@ public class TbKafkaConsumerTemplate extends AbstractTbQue protected void doSubscribe(List topicNames) { if (!topicNames.isEmpty()) { topicNames.forEach(admin::createTopicIfNotExists); - log.info("subscribe topics {}", topicNames); consumer.subscribe(topicNames); } else { log.info("unsubscribe due to empty topic list"); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java index 8711cbbcf1..a7f8cadd0d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/memory/InMemoryTbQueueConsumer.java @@ -31,7 +31,6 @@ public class InMemoryTbQueueConsumer implements TbQueueCon private volatile Set partitions; private volatile boolean stopped; private volatile boolean subscribed; - private volatile boolean queueDeleted; public InMemoryTbQueueConsumer(InMemoryStorage storage, String topic) { this.storage = storage; @@ -58,9 +57,15 @@ public class InMemoryTbQueueConsumer implements TbQueueCon subscribed = true; } + @Override + public void stop() { + stopped = true; + } + @Override public void unsubscribe() { stopped = true; + subscribed = false; } @Override @@ -104,16 +109,6 @@ public class InMemoryTbQueueConsumer implements TbQueueCon return stopped; } - @Override - public void onQueueDelete() { - queueDeleted = true; - } - - @Override - public boolean isQueueDeleted() { - return queueDeleted; - } - @Override public List getFullTopicNames() { return partitions.stream().map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList()); From 921b2ae4b7d41b58c616b79d3d62bce70ea6182b Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Tue, 17 Oct 2023 11:24:33 +0300 Subject: [PATCH 212/267] Tests for Rule Engine consumer manager --- .../controller/TenantControllerTest.java | 40 +- .../TbRuleEngineQueueConsumerManagerTest.java | 780 ++++++++++++++++++ 2 files changed, 801 insertions(+), 19 deletions(-) create mode 100644 application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java index 4b594d55f9..d1aefc097f 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java @@ -42,6 +42,7 @@ import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.User; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; @@ -54,12 +55,12 @@ import org.thingsboard.server.common.data.security.Authority; import org.thingsboard.server.common.data.tenant.profile.DefaultTenantProfileConfiguration; import org.thingsboard.server.common.data.tenant.profile.TenantProfileData; import org.thingsboard.server.common.data.tenant.profile.TenantProfileQueueConfiguration; -import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgMetaData; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.dao.service.DaoSqlTest; import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.discovery.PartitionService; @@ -67,9 +68,7 @@ import org.thingsboard.server.queue.discovery.PartitionService; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; -import java.util.Deque; import java.util.HashMap; -import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Random; @@ -680,26 +679,29 @@ public class TenantControllerTest extends AbstractControllerTest { .until(() -> partitionService.resolve(ServiceType.TB_RULE_ENGINE, MAIN_QUEUE_NAME, tenantId, tenantId) .getTenantId().get().isSysTenantId()); - Deque submittedMsgs = new LinkedList<>(); - await().atLeast(8, TimeUnit.SECONDS) // due to topic-deletion-delay - .atMost(20, TimeUnit.SECONDS) - .pollInterval(1, TimeUnit.SECONDS) - .untilAsserted(() -> { - TbMsg tbMsg = publishTbMsg(tenantId, tpi); - submittedMsgs.add(tbMsg.getId()); - - verify(queueAdmin, times(1)).deleteTopic(eq(isolatedTopic)); - }); - submittedMsgs.removeLast(); - for (UUID msgId : submittedMsgs) { - verify(actorContext, timeout(2000)).tell(argThat(msg -> { - return msg instanceof QueueToRuleEngineMsg && ((QueueToRuleEngineMsg) msg).getMsg().getId().equals(msgId); - })); + List submittedMsgs = new ArrayList<>(); + long timeLeft = TimeUnit.SECONDS.toMillis(7); // based on topic-deletion-delay + int msgs = 100; + for (int i = 1; i <= msgs; i++) { + TbMsg tbMsg = publishTbMsg(tenantId, tpi); + submittedMsgs.add(tbMsg.getId()); + Thread.sleep(timeLeft / msgs); } + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> { + verify(queueAdmin, times(1)).deleteTopic(eq(isolatedTopic)); + }); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> { + for (UUID msgId : submittedMsgs) { + verify(actorContext).tell(argThat(msg -> { + return msg instanceof QueueToRuleEngineMsg && ((QueueToRuleEngineMsg) msg).getMsg().getId().equals(msgId); + })); + } + }); } private TbMsg publishTbMsg(TenantId tenantId, TopicPartitionInfo tpi) { - TbMsg tbMsg = TbMsg.newMsg("POST_TELEMETRY_REQUEST", tenantId, TbMsgMetaData.EMPTY, "{\"test\":1}"); + TbMsg tbMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, tenantId, TbMsgMetaData.EMPTY, "{\"test\":1}"); TransportProtos.ToRuleEngineMsg msg = TransportProtos.ToRuleEngineMsg.newBuilder() .setTenantIdMSB(tenantId.getId().getMostSignificantBits()) .setTenantIdLSB(tenantId.getId().getLeastSignificantBits()) diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java new file mode 100644 index 0000000000..276e65ec39 --- /dev/null +++ b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java @@ -0,0 +1,780 @@ +/** + * Copyright © 2016-2023 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.queue.ruleengine; + +import lombok.Getter; +import lombok.SneakyThrows; +import lombok.extern.slf4j.Slf4j; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.testcontainers.shaded.org.apache.commons.lang3.RandomUtils; +import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.actors.ActorSystemContext; +import org.thingsboard.server.common.data.id.DeviceId; +import org.thingsboard.server.common.data.id.QueueId; +import org.thingsboard.server.common.data.id.TenantId; +import org.thingsboard.server.common.data.msg.TbMsgType; +import org.thingsboard.server.common.data.queue.ProcessingStrategy; +import org.thingsboard.server.common.data.queue.ProcessingStrategyType; +import org.thingsboard.server.common.data.queue.Queue; +import org.thingsboard.server.common.data.queue.SubmitStrategy; +import org.thingsboard.server.common.data.queue.SubmitStrategyType; +import org.thingsboard.server.common.msg.TbMsg; +import org.thingsboard.server.common.msg.TbMsgMetaData; +import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; +import org.thingsboard.server.common.msg.queue.ServiceType; +import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.common.stats.StatsFactory; +import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; +import org.thingsboard.server.queue.TbQueueAdmin; +import org.thingsboard.server.queue.TbQueueProducer; +import org.thingsboard.server.queue.common.AbstractTbQueueConsumerTemplate; +import org.thingsboard.server.queue.common.TbProtoQueueMsg; +import org.thingsboard.server.queue.discovery.PartitionService; +import org.thingsboard.server.queue.discovery.QueueKey; +import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; +import org.thingsboard.server.queue.provider.TbQueueProducerProvider; +import org.thingsboard.server.queue.provider.TbRuleEngineQueueFactory; +import org.thingsboard.server.service.queue.processing.TbRuleEngineProcessingStrategyFactory; +import org.thingsboard.server.service.queue.processing.TbRuleEngineSubmitStrategyFactory; +import org.thingsboard.server.service.stats.RuleEngineStatisticsService; + +import java.io.IOException; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.function.Supplier; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.awaitility.Awaitility.await; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.after; +import static org.mockito.Mockito.atLeast; +import static org.mockito.Mockito.atLeastOnce; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.mock; +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.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.verifyNoMoreInteractions; +import static org.mockito.Mockito.when; + +@Slf4j +@RunWith(MockitoJUnitRunner.class) +public class TbRuleEngineQueueConsumerManagerTest { + + @Mock + private ActorSystemContext actorContext; + @Mock + private StatsFactory statsFactory; + @Mock + private TbRuleEngineQueueFactory queueFactory; + @Mock + private RuleEngineStatisticsService statisticsService; + @Mock + private TbServiceInfoProvider serviceInfoProvider; + @Mock + private PartitionService partitionService; + @Mock + private TbQueueProducerProvider producerProvider; + private TbQueueProducer> ruleEngineMsgProducer; + @Mock + private TbQueueAdmin queueAdmin; + private TbRuleEngineConsumerContext ruleEngineConsumerContext; + + private TbRuleEngineQueueConsumerManager consumerManager; + private Queue queue; + + private Set consumers; + private boolean generateQueueMsgs; + private AtomicInteger totalConsumedMsgs; + private AtomicInteger totalProcessedMsgs; + + @Before + public void beforeEach() { + ruleEngineConsumerContext = new TbRuleEngineConsumerContext( + actorContext, statsFactory, spy(new TbRuleEngineSubmitStrategyFactory()), + spy(new TbRuleEngineProcessingStrategyFactory()), queueFactory, statisticsService, + serviceInfoProvider, partitionService, producerProvider, queueAdmin + ); + consumers = ConcurrentHashMap.newKeySet(); + generateQueueMsgs = true; + totalConsumedMsgs = new AtomicInteger(); + totalProcessedMsgs = new AtomicInteger(); + doAnswer(inv -> { + QueueToRuleEngineMsg msg = inv.getArgument(0); + msg.getMsg().getCallback().onSuccess(); + totalProcessedMsgs.incrementAndGet(); + log.trace("totalProcessedMsgs = {}", totalProcessedMsgs); + return null; + }).when(actorContext).tell(any()); + ruleEngineMsgProducer = mock(TbQueueProducer.class); + when(producerProvider.getRuleEngineMsgProducer()).thenReturn(ruleEngineMsgProducer); + ruleEngineConsumerContext.setMgmtThreadPoolSize(2); + ruleEngineConsumerContext.setTopicDeletionDelayInSec(5); + ruleEngineConsumerContext.init(); + ruleEngineConsumerContext.setReady(false); + + queue = new Queue(); + queue.setName("Test"); + queue.setTenantId(TenantId.SYS_TENANT_ID); + queue.setId(new QueueId(UUID.randomUUID())); + queue.setTopic("tb_test"); + queue.setPartitions(10); + queue.setConsumerPerPartition(true); + queue.setPollInterval(250); + queue.setPackProcessingTimeout(2000); + SubmitStrategy submitStrategy = new SubmitStrategy(); + submitStrategy.setType(SubmitStrategyType.BURST); + submitStrategy.setBatchSize(200); + queue.setSubmitStrategy(submitStrategy); + ProcessingStrategy processingStrategy = new ProcessingStrategy(); + processingStrategy.setType(ProcessingStrategyType.SKIP_ALL_FAILURES_AND_TIMED_OUT); + processingStrategy.setRetries(0); + queue.setProcessingStrategy(processingStrategy); + + doAnswer(i -> { + TestConsumer consumer = spy(new TestConsumer(queue.getTopic())); + if (generateQueueMsgs) { + consumer.setUpTestMsg(); + } + consumers.add(consumer); + return consumer; + }).when(queueFactory).createToRuleEngineMsgConsumer(any()); + + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue); + consumerManager = new TbRuleEngineQueueConsumerManager(ruleEngineConsumerContext, queueKey); + } + + @After + public void afterEach() { + consumerManager.stop(); + ruleEngineConsumerContext.stop(); + + if (generateQueueMsgs) { + await().atMost(1, TimeUnit.SECONDS) + .until(() -> totalProcessedMsgs.get() == totalConsumedMsgs.get()); + } + log.debug("totalConsumedMsgs = {}, totalProcessedMsgs = {}", totalConsumedMsgs.get(), totalProcessedMsgs.get()); + } + + @Test + public void testInit_consumerPerPartition() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + + Set partitions = createTpis(2, 3, 4); + consumerManager.update(partitions); + partitions = createTpis(3, 4, 5); + consumerManager.update(partitions); + partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + // simulated multiple partition change events before consumer is ready; only latest partitions should be processed + verifyNoInteractions(queueFactory); + + ruleEngineConsumerContext.setReady(true); + await().atMost(2, TimeUnit.SECONDS) + .until(() -> consumers.size() == 3); + for (TopicPartitionInfo partition : partitions) { + TestConsumer consumer = getConsumer(partition); + verifySubscribedAndLaunched(consumer, Set.of(partition)); + } + } + + @Test + public void testInit_singleConsumer() { + queue.setConsumerPerPartition(false); + consumerManager.init(queue); + + Set partitions = createTpis(2, 3, 4); + consumerManager.update(partitions); + partitions = createTpis(3, 4, 5); + consumerManager.update(partitions); + partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + + verifyNoInteractions(queueFactory); + + ruleEngineConsumerContext.setReady(true); + await().atMost(2, TimeUnit.SECONDS) + .until(() -> consumers.size() == 1); + TestConsumer consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + } + + @Test + public void testPartitionsUpdate_singleConsumer() { + queue.setConsumerPerPartition(false); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + + Set partitions = Collections.emptySet(); + consumerManager.update(partitions); + verify(queueFactory, after(1000).never()).createToRuleEngineMsgConsumer(any()); + + partitions = createTpis(1); + consumerManager.update(partitions); + TestConsumer consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + + partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + verifySubscribedAndLaunched(consumer, partitions); + + partitions = createTpis(4, 5, 6); + consumerManager.update(partitions); + verifySubscribedAndLaunched(consumer, partitions); + + partitions = Collections.emptySet(); + consumerManager.update(partitions); + verifyUnsubscribedAndStopped(consumer); + + partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + } + + @Test + public void testPartitionsUpdate_consumerPerPartition() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + + consumerManager.update(Collections.emptySet()); + verify(queueFactory, after(1000).never()).createToRuleEngineMsgConsumer(any()); + + consumerManager.update(createTpis(1)); + TestConsumer consumer1 = getConsumer(1); + verifySubscribedAndLaunched(consumer1, 1); + + consumerManager.update(createTpis(1, 2, 3)); + TestConsumer consumer2 = getConsumer(2); + TestConsumer consumer3 = getConsumer(3); + verifySubscribedAndLaunched(consumer2, 2); + verifySubscribedAndLaunched(consumer3, 3); + verifyNotTouched(consumer1); + + consumerManager.update(createTpis(3, 4, 5)); + TestConsumer consumer4 = getConsumer(4); + TestConsumer consumer5 = getConsumer(5); + verifySubscribedAndLaunched(consumer4, 4); + verifySubscribedAndLaunched(consumer5, 5); + verifyUnsubscribedAndStopped(consumer1); + verifyUnsubscribedAndStopped(consumer2); + verifyNotTouched(consumer3); + + consumerManager.update(Collections.emptySet()); + verifyUnsubscribedAndStopped(consumer3); + verifyUnsubscribedAndStopped(consumer4); + verifyUnsubscribedAndStopped(consumer5); + + consumerManager.update(createTpis(1, 2, 3)); + consumer1 = getConsumer(1); + consumer2 = getConsumer(2); + consumer3 = getConsumer(3); + verifySubscribedAndLaunched(consumer1, 1); + verifySubscribedAndLaunched(consumer2, 2); + verifySubscribedAndLaunched(consumer3, 3); + } + + @Test + public void testConfigUpdate_singleConsumer() { + queue.setConsumerPerPartition(false); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + TestConsumer consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + + Queue newConfig = JacksonUtil.clone(queue); + newConfig.setPollInterval(queue.getPollInterval() / 2); + newConfig.setPartitions(queue.getPartitions() / 2); + newConfig.setPackProcessingTimeout(queue.getPackProcessingTimeout() * 2); + newConfig.getSubmitStrategy().setType(SubmitStrategyType.SEQUENTIAL_BY_ORIGINATOR); + newConfig.getProcessingStrategy().setType(ProcessingStrategyType.RETRY_ALL); + consumerManager.update(newConfig); + + await().atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + verify(consumer, atLeastOnce()).poll(eq((long) newConfig.getPollInterval())); + verify(ruleEngineConsumerContext.getSubmitStrategyFactory(), atLeastOnce()).newInstance(any(), eq(newConfig.getSubmitStrategy())); + verify(ruleEngineConsumerContext.getProcessingStrategyFactory(), atLeastOnce()).newInstance(any(), eq(newConfig.getProcessingStrategy())); + }); + } + + @Test + public void testConfigUpdate_consumerPerPartition() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + TestConsumer consumer1 = getConsumer(1); + TestConsumer consumer2 = getConsumer(2); + TestConsumer consumer3 = getConsumer(3); + verifySubscribedAndLaunched(consumer1, 1); + verifySubscribedAndLaunched(consumer2, 2); + verifySubscribedAndLaunched(consumer3, 3); + + Queue newConfig = JacksonUtil.clone(queue); + newConfig.setPollInterval(queue.getPollInterval() / 2); + newConfig.setPartitions(queue.getPartitions() / 2); + newConfig.setPackProcessingTimeout(queue.getPackProcessingTimeout() * 2); + newConfig.getSubmitStrategy().setType(SubmitStrategyType.SEQUENTIAL_BY_ORIGINATOR); + newConfig.getProcessingStrategy().setType(ProcessingStrategyType.RETRY_ALL); + consumerManager.update(newConfig); + + await().atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + verify(consumer1, atLeastOnce()).poll(eq((long) newConfig.getPollInterval())); + verify(consumer2, atLeastOnce()).poll(eq((long) newConfig.getPollInterval())); + verify(consumer3, atLeastOnce()).poll(eq((long) newConfig.getPollInterval())); + }); + verifyNotTouched(consumer1); + verifyNotTouched(consumer2); + verifyNotTouched(consumer3); + } + + @Test + public void testConfigUpdate_fromSingleToConsumerPerPartition() { + queue.setConsumerPerPartition(false); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + TestConsumer consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + + Queue newConfig = JacksonUtil.clone(queue); + newConfig.setConsumerPerPartition(true); + consumerManager.update(newConfig); + + verifyUnsubscribedAndStopped(consumer); + verifySubscribedAndLaunched(getConsumer(1), 1); + verifySubscribedAndLaunched(getConsumer(2), 2); + verifySubscribedAndLaunched(getConsumer(3), 3); + } + + @Test + public void testConfigUpdate_fromConsumerPerPartitionToSingle() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2, 3); + consumerManager.update(partitions); + TestConsumer consumer1 = getConsumer(1); + TestConsumer consumer2 = getConsumer(2); + TestConsumer consumer3 = getConsumer(3); + verifySubscribedAndLaunched(consumer1, 1); + verifySubscribedAndLaunched(consumer2, 2); + verifySubscribedAndLaunched(consumer3, 3); + + Queue newConfig = JacksonUtil.clone(queue); + newConfig.setConsumerPerPartition(false); + consumerManager.update(newConfig); + + verifyUnsubscribedAndStopped(consumer1); + verifyUnsubscribedAndStopped(consumer2); + verifyUnsubscribedAndStopped(consumer3); + verifySubscribedAndLaunched(getConsumer(), partitions); + } + + @Test + public void testStop() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + consumerManager.update(createTpis(1)); + TestConsumer consumer = getConsumer(1); + verifySubscribedAndLaunched(consumer, 1); + verify(queueFactory, times(1)).createToRuleEngineMsgConsumer(any()); + + consumerManager.stop(); + consumerManager.update(createTpis(1, 2, 3, 4)); // to check that no new tasks after stop are processed + consumerManager.update(createTpis(5, 6, 7)); + + verifyUnsubscribedAndStopped(consumer); + verifyNoMoreInteractions(queueFactory); + } + + @Test + public void testDelete_consumerPerPartition() { + queue.setConsumerPerPartition(true); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2); + consumerManager.update(partitions); + TestConsumer consumer1 = getConsumer(1); + TestConsumer consumer2 = getConsumer(2); + verifySubscribedAndLaunched(consumer1, 1); + verifySubscribedAndLaunched(consumer2, 2); + verifyMsgProcessed(consumer1.testMsg); + verifyMsgProcessed(consumer2.testMsg); + + consumerManager.delete(); + + await().atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + verify(ruleEngineMsgProducer).send(any(), any(), any()); + }); + clearInvocations(actorContext); + verify(consumer1, never()).unsubscribe(); + verify(consumer2, never()).unsubscribe(); + int msgCount1 = consumer1.msgCount; + int msgCount2 = consumer2.msgCount; + + await().atLeast(4, TimeUnit.SECONDS) // based on topicDeletionDelayInSec + .atMost(7, TimeUnit.SECONDS) + .untilAsserted(() -> { + partitions.stream() + .map(TopicPartitionInfo::getFullTopicName) + .forEach(topic -> { + verify(queueAdmin).deleteTopic(eq(topic)); + }); + }); + verify(consumer1).unsubscribe(); + verify(consumer2).unsubscribe(); + + int movedMsgs1 = consumer1.msgCount - msgCount1; + int movedMsgs2 = consumer2.msgCount - msgCount2; + int totalMovedMsgs = movedMsgs1 + movedMsgs2; + assertThat(totalMovedMsgs).isGreaterThan(10); + verify(ruleEngineMsgProducer, atLeast(totalMovedMsgs)).send(any(), any(), any()); + verify(actorContext, never()).tell(any()); + generateQueueMsgs = false; + } + + @Test + public void testDelete_singleConsumer() { + queue.setConsumerPerPartition(false); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + Set partitions = createTpis(1, 2); + consumerManager.update(partitions); + TestConsumer consumer = getConsumer(); + verifySubscribedAndLaunched(consumer, partitions); + verifyMsgProcessed(consumer.testMsg); + + consumerManager.delete(); + + await().atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + verify(ruleEngineMsgProducer).send(any(), any(), any()); + }); + clearInvocations(actorContext); + verify(consumer, never()).unsubscribe(); + int msgCount = consumer.msgCount; + + await().atLeast(4, TimeUnit.SECONDS) + .atMost(7, TimeUnit.SECONDS) + .untilAsserted(() -> { + partitions.stream() + .map(TopicPartitionInfo::getFullTopicName) + .forEach(topic -> { + verify(queueAdmin).deleteTopic(eq(topic)); + }); + }); + verify(consumer).unsubscribe(); + + int movedMsgs = consumer.msgCount - msgCount; + assertThat(movedMsgs).isGreaterThan(10); + verify(ruleEngineMsgProducer, atLeast(movedMsgs)).send(any(), any(), any()); + verify(actorContext, never()).tell(any()); + generateQueueMsgs = false; + } + + @Test + public void testManyDifferentUpdates() throws Exception { + queue.setConsumerPerPartition(RandomUtils.nextBoolean()); + consumerManager.init(queue); + ruleEngineConsumerContext.setReady(true); + + Supplier queueConfigUpdater = () -> { + Queue oldConfig = consumerManager.getQueue(); + Queue newConfig = JacksonUtil.clone(oldConfig); + newConfig.setConsumerPerPartition(RandomUtils.nextBoolean()); + newConfig.setPollInterval(RandomUtils.nextInt(100, 501)); + newConfig.setPartitions(RandomUtils.nextInt(1, 10)); + newConfig.setPackProcessingTimeout(RandomUtils.nextLong(100, 5001)); + newConfig.getSubmitStrategy().setType(SubmitStrategyType.values()[RandomUtils.nextInt(0, SubmitStrategyType.values().length)]); + newConfig.getProcessingStrategy().setType(ProcessingStrategyType.values()[RandomUtils.nextInt(0, ProcessingStrategyType.values().length)]); + log.info("Generated new config: consumerPerPartition={}, pollInterval={}, processingStrategy={}", + newConfig.isConsumerPerPartition(), newConfig.getPollInterval(), newConfig.getProcessingStrategy().getType()); + return newConfig; + }; + Supplier> partitionsUpdater = () -> { + int partitionsCount = RandomUtils.nextInt(0, 20); + int[] partitions = IntStream.generate(() -> RandomUtils.nextInt(0, 20)) + .distinct().limit(partitionsCount) + .sorted().toArray(); + log.info("Generated new partitions: {}", Arrays.toString(partitions)); + return createTpis(partitions); + }; + + int iterations = 100; + Queue latestConfig = queue; + Set latestPartitions = Collections.emptySet(); + for (int i = 1; i <= iterations; i++) { + boolean updateQueueConfig = RandomUtils.nextBoolean(); + boolean updatePartitions = !updateQueueConfig; + if (updateQueueConfig) { + latestConfig = queueConfigUpdater.get(); + consumerManager.update(latestConfig); + } + if (updatePartitions) { + latestPartitions = partitionsUpdater.get(); + consumerManager.update(latestPartitions); + } + Thread.sleep(RandomUtils.nextLong(0, 200)); + } + if (latestPartitions.isEmpty()) { + do { + latestPartitions = partitionsUpdater.get(); + } while (latestPartitions.isEmpty()); + consumerManager.update(latestPartitions); + } + + Queue expectedConfig = latestConfig; + Set expectedPartitions = latestPartitions; + await().atMost(5, TimeUnit.SECONDS) + .untilAsserted(() -> { + assertThat(consumerManager.getQueue()).isEqualTo(expectedConfig); + assertThat(consumerManager.getPartitions()).isEqualTo(expectedPartitions); + }); + + if (expectedConfig.isConsumerPerPartition()) { + await().atMost(5, TimeUnit.SECONDS).until(() -> { + for (TopicPartitionInfo partition : expectedPartitions) { + if (consumers.stream().noneMatch(consumer -> consumer.subscribed && + consumer.pollingStarted && Set.of(partition).equals(consumer.getPartitions()))) { + return false; + } + } + return consumers.size() == expectedPartitions.size(); + }); + } else { + await().atMost(5, TimeUnit.SECONDS).until(() -> { + return consumers.size() == 1 && consumers.stream() + .anyMatch(consumer -> consumer.subscribed && consumer.pollingStarted && + expectedPartitions.equals(consumer.getPartitions())); + }); + } + Mockito.reset(ruleEngineConsumerContext.getSubmitStrategyFactory()); + Mockito.reset(ruleEngineConsumerContext.getProcessingStrategyFactory()); + consumers.forEach(Mockito::clearInvocations); + + await().atMost(5, TimeUnit.SECONDS).untilAsserted(() -> { + for (TestConsumer consumer : consumers) { + verify(consumer, atLeastOnce().description("consumer " + consumer.topics)).poll(expectedConfig.getPollInterval()); + } + verify(ruleEngineConsumerContext.getSubmitStrategyFactory(), atLeastOnce()).newInstance(any(), eq(expectedConfig.getSubmitStrategy())); + verify(ruleEngineConsumerContext.getProcessingStrategyFactory(), atLeastOnce()).newInstance(any(), eq(expectedConfig.getProcessingStrategy())); + }); + } + + /* + * 2023-10-15 18:34:06,090 [main] INFO o.t.s.s.q.r.TbRuleEngineQueueConsumerManagerTest - Generated new partitions: [0, 1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 13, 15, 16, 17, 18, 19] +2023-10-15 18:34:06,090 [main] INFO o.t.s.s.q.r.TbRuleEngineQueueConsumerManagerTest - Generated new config: consumerPerPartition=false, pollInterval=299, processingStrategy=RETRY_FAILED + * */ + + private void verifySubscribedAndLaunched(TestConsumer consumer, Set expectedPartitions) { + await().atMost(2, TimeUnit.SECONDS) + .until(() -> consumer.subscribed && consumer.getPartitions().equals(expectedPartitions) && consumer.pollingStarted); + verify(consumer, times(1)).subscribe(any()); + verify(consumer).subscribe(eq(expectedPartitions)); + verify(consumer).doSubscribe(argThat(topics -> topics.containsAll(expectedPartitions.stream() + .map(TopicPartitionInfo::getFullTopicName).collect(Collectors.toList())))); + verify(consumer, atLeastOnce()).poll(eq((long) queue.getPollInterval())); + verify(consumer, atLeastOnce()).doPoll(eq((long) queue.getPollInterval())); + verify(consumer, never()).unsubscribe(); + Mockito.reset(consumer); + } + + private void verifySubscribedAndLaunched(TestConsumer consumer, int... expectedPartitions) { + verifySubscribedAndLaunched(consumer, createTpis(expectedPartitions)); + } + + private void verifyUnsubscribedAndStopped(TestConsumer consumer) { + await().atMost(2, TimeUnit.SECONDS) + .until(() -> !consumer.subscribed && !consumer.topics.isEmpty()); + verify(consumer, never()).subscribe(any()); + verify(consumer, never()).doSubscribe(any()); + assertThat(consumers).doesNotContain(consumer); + Mockito.reset(consumer); + } + + private void verifyNotTouched(TestConsumer consumer) { + verify(consumer, never()).subscribe(any()); + verify(consumer, never()).subscribe(); + verify(consumer, never()).doSubscribe(any()); + verify(consumer, never()).unsubscribe(); + verify(consumer, never()).doUnsubscribe(); + } + + private void verifyMsgProcessed(TbMsg tbMsg) { + await().atMost(2, TimeUnit.SECONDS).untilAsserted(() -> { + verify(actorContext, atLeastOnce()).tell(argThat(msg -> { + return ((QueueToRuleEngineMsg) msg).getMsg().getId().equals(tbMsg.getId()); + })); + }); + } + + // for consumer-per-partition + private TestConsumer getConsumer(TopicPartitionInfo tpi) { + return await().atMost(5, TimeUnit.SECONDS) + .until(() -> consumers.stream() + .filter(consumer -> consumer.getPartitions() != null && + consumer.getPartitions().size() == 1 && + consumer.getPartitions().contains(tpi)) + .findFirst().orElse(null), Objects::nonNull); + } + + private TestConsumer getConsumer(int partition) { + return await().atMost(5, TimeUnit.SECONDS) + .until(() -> consumers.stream() + .filter(consumer -> consumer.getPartitions() != null && + consumer.getPartitions().size() == 1 && + consumer.getPartitions().stream() + .anyMatch(tpi -> tpi.getPartition().get().equals(partition))) + .findFirst().orElse(null), Objects::nonNull); + } + + // for single consumer + private TestConsumer getConsumer() { + return await().atMost(5, TimeUnit.SECONDS) + .until(() -> consumers.size() == 1 ? consumers.iterator().next() : null, Objects::nonNull); + } + + private Set createTpis(int... partitions) { + return Arrays.stream(partitions) + .mapToObj(n -> TopicPartitionInfo.builder() + .tenantId(queue.getTenantId()) + .topic(queue.getTopic()) + .partition(n) + .myPartition(true) + .build()) + .collect(Collectors.toSet()); + } + + + class TestConsumer extends AbstractTbQueueConsumerTemplate> { + + @Getter + private List topics; + + private boolean subscribed; + private boolean pollingStarted; + + private TbMsg testMsg; + private int msgCount; + + public TestConsumer(String topic) { + super(topic); + } + + @SneakyThrows + @Override + protected List doPoll(long durationInMillis) { + log.debug("doPoll({} ms)", durationInMillis); + if (!subscribed) { + throw new IllegalStateException("Cannot poll because not subscribed"); + } + pollingStarted = true; + if (testMsg != null && RandomUtils.nextBoolean()) { + Thread.sleep(100); + return List.of(testMsg); + } + return Collections.emptyList(); + } + + @Override + protected TbProtoQueueMsg decode(TbMsg tbMsg) throws IOException { + log.debug("decode()"); + UUID tenantId = UUID.randomUUID(); + return new TbProtoQueueMsg<>(UUID.randomUUID(), ToRuleEngineMsg.newBuilder() + .setTenantIdMSB(tenantId.getMostSignificantBits()) + .setTenantIdLSB(tenantId.getLeastSignificantBits()) + .addRelationTypes("Success") + .setTbMsg(TbMsg.toByteString(tbMsg)) + .build()); + } + + @Override + protected void doSubscribe(List topicNames) { + log.debug("doSubscribe({})", topicNames); + this.topics = topicNames; + subscribed = true; + } + + @Override + protected void doCommit() { + if (!subscribed) { + throw new IllegalStateException("Cannot commit because not subscribed"); + } + msgCount++; + log.debug("doCommit() totalConsumedMsgs = {}", totalConsumedMsgs.incrementAndGet()); + } + + @Override + public void unsubscribe() { + super.unsubscribe(); + consumers.remove(this); + } + + @Override + protected void doUnsubscribe() { + log.debug("doUnsubscribe()"); + if (!subscribed) { + throw new IllegalStateException("Already unsubscribed!"); + } + subscribed = false; + } + + @Override + protected boolean isLongPollingSupported() { + return false; + } + + public Set getPartitions() { + return partitions; + } + + public void setUpTestMsg() { + testMsg = TbMsg.newMsg(TbMsgType.POST_TELEMETRY_REQUEST, new DeviceId(UUID.randomUUID()), new TbMsgMetaData(), "{}"); + } + } + +} From ea4eadb47f9184326f04f05e5461744376368d06 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Wed, 18 Oct 2023 14:20:41 +0300 Subject: [PATCH 213/267] Cancelling consumer loop task on stop --- .../DefaultTbRuleEngineConsumerService.java | 1 + .../service/queue/ruleengine/QueueEvent.java | 2 +- .../queue/ruleengine/TbQueueConsumerTask.java | 34 +++++++-- .../TbRuleEngineConsumerContext.java | 10 +-- .../TbRuleEngineQueueConsumerManager.java | 70 +++++++++++-------- .../TbRuleEngineQueueConsumerManagerTest.java | 10 +-- 6 files changed, 78 insertions(+), 49 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index 64139530b1..3f05a5b923 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -126,6 +126,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< @Override protected void stopConsumers() { consumers.values().forEach(TbRuleEngineQueueConsumerManager::stop); + consumers.values().forEach(TbRuleEngineQueueConsumerManager::awaitStop); ctx.stop(); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java index a4a3bcc59a..86955be7e7 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/QueueEvent.java @@ -19,6 +19,6 @@ import java.io.Serializable; public enum QueueEvent implements Serializable { - PARTITION_CHANGE, CONFIG_UPDATE, STOP, DELETE + PARTITION_CHANGE, CONFIG_UPDATE, DELETE } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java index a0a5579951..2e3a4676e8 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java @@ -15,7 +15,8 @@ */ package org.thingsboard.server.service.queue.ruleengine; -import lombok.Data; +import lombok.Getter; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; @@ -23,16 +24,26 @@ import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import java.util.Set; +import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; -@Data +@RequiredArgsConstructor @Slf4j public class TbQueueConsumerTask { + @Getter private final Object key; + @Getter private final TbQueueConsumer> consumer; - private volatile Future task; + + private Future task; + private CountDownLatch completionLatch; + + public void setTask(Future task) { + this.task = task; + this.completionLatch = new CountDownLatch(1); + } public void subscribe(Set partitions) { log.trace("[{}] Subscribing to partitions: {}", key, partitions); @@ -42,23 +53,32 @@ public class TbQueueConsumerTask { public void initiateStop() { log.debug("[{}] Initiating stop", key); consumer.stop(); + if (isRunning()) { + task.cancel(true); + } } - public void awaitFinish() { + public void awaitCompletion() { log.trace("[{}] Awaiting finish", key); if (isRunning()) { try { - task.get(60, TimeUnit.SECONDS); - task = null; + if (!completionLatch.await(30, TimeUnit.SECONDS)) { + throw new IllegalStateException("timeout of 30 seconds expired"); + } } catch (Exception e) { log.warn("[{}] Failed to await for consumer to stop", key, e); } + task = null; } log.trace("[{}] Awaited finish", key); } public boolean isRunning() { - return task != null && !task.isDone(); + return task != null; + } + + public void finished() { + completionLatch.countDown(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java index 325a685972..f4c8e4c2ae 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -36,7 +36,6 @@ import javax.annotation.PostConstruct; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; @Component @TbRuleEngineComponent @@ -83,12 +82,7 @@ public class TbRuleEngineConsumerContext { public void stop() { scheduler.shutdownNow(); - consumersExecutor.shutdown(); - mgmtExecutor.shutdown(); - try { - mgmtExecutor.awaitTermination(15, TimeUnit.SECONDS); - } catch (InterruptedException e) { - log.warn("Failed to await mgmtExecutor termination"); - } + consumersExecutor.shutdownNow(); + mgmtExecutor.shutdownNow(); } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java index dc3966d0d2..3a7b2f15d8 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java @@ -85,7 +85,13 @@ public class TbRuleEngineQueueConsumerManager { } public void init(Queue queue) { - doInit(queue); + this.queue = queue; + if (queue.isConsumerPerPartition()) { + this.consumerWrapper = new ConsumerPerPartitionWrapper(); + } else { + this.consumerWrapper = new SingleConsumerWrapper(); + } + log.debug("[{}] Initialized consumer for queue: {}", queueKey, queue); } public void update(Queue queue) { @@ -96,10 +102,6 @@ public class TbRuleEngineQueueConsumerManager { addTask(new TbQueueConsumerManagerTask(QueueEvent.PARTITION_CHANGE, partitions)); } - public void stop() { - addTask(new TbQueueConsumerManagerTask(QueueEvent.STOP)); - } - public void delete() { addTask(new TbQueueConsumerManagerTask(QueueEvent.DELETE)); } @@ -135,20 +137,22 @@ public class TbRuleEngineQueueConsumerManager { newPartitions = task.getPartitions(); } else if (task.getEvent() == QueueEvent.CONFIG_UPDATE) { newConfiguration = task.getQueue(); - } else if (task.getEvent() == QueueEvent.STOP) { - doStop(); - return; } else if (task.getEvent() == QueueEvent.DELETE) { doDelete(); return; } } + if (stopped) { + return; + } if (newConfiguration != null) { doUpdate(newConfiguration); } if (newPartitions != null) { doUpdate(newPartitions); } + } catch (Exception e) { + log.error("[{}] Failed to process tasks", queueKey, e); } finally { lock.unlock(); } @@ -159,16 +163,6 @@ public class TbRuleEngineQueueConsumerManager { }); } - private void doInit(Queue queue) { - this.queue = queue; - if (queue.isConsumerPerPartition()) { - consumerWrapper = new ConsumerPerPartitionWrapper(); - } else { - consumerWrapper = new SingleConsumerWrapper(); - } - log.debug("[{}] Initialized consumer for queue: {}", queueKey, queue); - } - private void doUpdate(Queue newQueue) { log.info("[{}] Processing queue update: {}", queueKey, newQueue); var oldQueue = this.queue; @@ -179,12 +173,12 @@ public class TbRuleEngineQueueConsumerManager { } if (oldQueue == null) { - doInit(queue); + init(queue); } else if (newQueue.isConsumerPerPartition() != oldQueue.isConsumerPerPartition()) { consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::initiateStop); - consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitCompletion); - doInit(queue); + init(queue); if (partitions != null) { doUpdate(partitions); // even if partitions number was changed, there can be no partition change event } @@ -200,17 +194,21 @@ public class TbRuleEngineQueueConsumerManager { consumerWrapper.updatePartitions(partitions); } - private void doStop() { + public void stop() { + log.debug("[{}] Stopping consumers", queueKey); consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::initiateStop); - consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); - log.debug("[{}] Unsubscribed and stopped consumers", queueKey); stopped = true; } + public void awaitStop() { + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitCompletion); + log.debug("[{}] Unsubscribed and stopped consumers", queueKey); + } + private void doDelete() { stopped = true; log.info("[{}] Handling queue deletion", queueKey); - consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitFinish); + consumerWrapper.getConsumers().forEach(TbQueueConsumerTask::awaitCompletion); List>> queueConsumers = consumerWrapper.getConsumers().stream() .map(TbQueueConsumerTask::getConsumer).collect(Collectors.toList()); @@ -240,6 +238,7 @@ public class TbRuleEngineQueueConsumerManager { Future consumerLoop = ctx.getConsumersExecutor().submit(() -> { ThingsBoardThreadFactory.updateCurrentThreadName(consumerTask.getKey().toString()); consumerLoop(consumerTask.getConsumer()); + consumerTask.finished(); }); consumerTask.setTask(consumerLoop); } @@ -253,7 +252,7 @@ public class TbRuleEngineQueueConsumerManager { } processMsgs(msgs, consumer, queue); } catch (Exception e) { - if (!stopped) { + if (!consumer.isStopped()) { log.warn("Failed to process messages from queue", e); try { Thread.sleep(ctx.getPollDuration()); @@ -279,7 +278,7 @@ public class TbRuleEngineQueueConsumerManager { TbMsgPackProcessingContext packCtx = new TbMsgPackProcessingContext(queue.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); submitStrategy.submitAttempt((id, msg) -> submitMessage(packCtx, id, msg)); - final boolean timeout = !packCtx.await(queue.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); + final boolean timeout = !awaitPackProcessing(packCtx, queue.getPackProcessingTimeout(), true); TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(queue.getName(), timeout, packCtx); if (timeout) { @@ -307,6 +306,19 @@ public class TbRuleEngineQueueConsumerManager { } } + private boolean awaitPackProcessing(TbMsgPackProcessingContext packCtx, long processingTimeout, boolean ignoreInterrupt) throws InterruptedException { + try { + return packCtx.await(processingTimeout, TimeUnit.MILLISECONDS); + } catch (InterruptedException e) { + if (ignoreInterrupt) { + log.debug("Interrupt happened while waiting for pack processing, trying to await one more time"); + return awaitPackProcessing(packCtx, processingTimeout, false); + } else { + throw new RuntimeException("Failed to await pack processing due to thread interrupt", e); + } + } + } + private TbRuleEngineSubmitStrategy getSubmitStrategy(Queue queue) { return ctx.getSubmitStrategyFactory().newInstance(queue.getName(), queue.getSubmitStrategy()); } @@ -430,7 +442,7 @@ public class TbRuleEngineQueueConsumerManager { consumers.get(tpi).initiateStop(); }); removedPartitions.forEach((tpi) -> { - consumers.remove(tpi).awaitFinish(); + consumers.remove(tpi).awaitCompletion(); }); addedPartitions.forEach((tpi) -> { @@ -457,7 +469,7 @@ public class TbRuleEngineQueueConsumerManager { if (partitions.isEmpty()) { if (consumer != null && consumer.isRunning()) { consumer.initiateStop(); - consumer.awaitFinish(); + consumer.awaitCompletion(); } consumer = null; return; diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java index 276e65ec39..20b765da6d 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java @@ -180,13 +180,16 @@ public class TbRuleEngineQueueConsumerManagerTest { @After public void afterEach() { consumerManager.stop(); + consumerManager.awaitStop(); ruleEngineConsumerContext.stop(); if (generateQueueMsgs) { - await().atMost(1, TimeUnit.SECONDS) - .until(() -> totalProcessedMsgs.get() == totalConsumedMsgs.get()); + await().atMost(2, TimeUnit.SECONDS) + .untilAsserted(() -> { + log.debug("totalConsumedMsgs = {}, totalProcessedMsgs = {}", totalConsumedMsgs.get(), totalProcessedMsgs.get()); + assertThat(totalProcessedMsgs.get()).isEqualTo(totalConsumedMsgs.get()); + }); } - log.debug("totalConsumedMsgs = {}, totalProcessedMsgs = {}", totalConsumedMsgs.get(), totalProcessedMsgs.get()); } @Test @@ -510,7 +513,6 @@ public class TbRuleEngineQueueConsumerManagerTest { verify(consumer).unsubscribe(); int movedMsgs = consumer.msgCount - msgCount; - assertThat(movedMsgs).isGreaterThan(10); verify(ruleEngineMsgProducer, atLeast(movedMsgs)).send(any(), any(), any()); verify(actorContext, never()).tell(any()); generateQueueMsgs = false; From 5108e98f38631ff4f828cb014965b4836ef475a2 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 19 Oct 2023 11:03:53 +0300 Subject: [PATCH 214/267] Minor refactoring --- .../service/queue/ruleengine/TbRuleEngineConsumerContext.java | 2 +- application/src/main/resources/thingsboard.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java index f4c8e4c2ae..b18df6b62b 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -74,7 +74,7 @@ public class TbRuleEngineConsumerContext { private volatile boolean isReady = false; @PostConstruct - public void init() { + void init() { this.consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); this.mgmtExecutor = Executors.newFixedThreadPool(mgmtThreadPoolSize, ThingsBoardThreadFactory.forName("tb-rule-engine-mgmt")); this.scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-scheduler")); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 6f51413ccd..be01c95fad 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -1304,7 +1304,7 @@ queue: max-pause-between-retries: "${TB_QUEUE_RE_SQ_PROCESSING_STRATEGY_MAX_RETRY_PAUSE:5}" # Max allowed time in seconds for pause between retries. # After a queue is deleted (or profile's isolation option was disabled), Rule Engine will continue reading related topics during this period, before deleting the actual topics topic-deletion-delay: "${TB_QUEUE_RULE_ENGINE_TOPIC_DELETION_DELAY_SEC:15}" - # Size of the thread pool that handles management operations such as subscribe, unsubscribe, queue delete, etc. + # Size of the thread pool that handles such operations as partition changes, config updates, queue deletion management-thread-pool-size: "${TB_QUEUE_RULE_ENGINE_MGMT_THREAD_POOL_SIZE:12}" transport: # For high priority notifications that require minimum latency and processing time From a0505ee0e4353ef23bb272dad705ba766d8f82ce Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 12:42:45 +0300 Subject: [PATCH 215/267] UI: Outdoor environment: Humidity widgets. --- .../widget_bundles/outdoor_environment.json | 12 ++++++- .../horizontal_humidity_card.json | 28 +++++++++++++++++ ...izontal_humidity_card_with_background.json | 28 +++++++++++++++++ .../system/widget_types/humidity_card.json | 28 +++++++++++++++++ .../humidity_card_with_background.json | 28 +++++++++++++++++ .../widget_types/humidity_chart_card.json | 31 +++++++++++++++++++ .../humidity_chart_card_with_background.json | 31 +++++++++++++++++++ .../widget_types/humidity_progress_bar.json | 29 +++++++++++++++++ ...humidity_progress_bar_with_background.json | 29 +++++++++++++++++ .../simple_humidity_chart_card.json | 31 +++++++++++++++++++ ...e_humidity_chart_card_with_background.json | 31 +++++++++++++++++++ 11 files changed, 305 insertions(+), 1 deletion(-) create mode 100644 application/src/main/data/json/system/widget_types/horizontal_humidity_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_card.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_humidity_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_humidity_chart_card_with_background.json diff --git a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json index a21eaf65f0..71c148d22c 100644 --- a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json +++ b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json @@ -15,6 +15,16 @@ "temperature_chart_card", "temperature_chart_card_with_background", "simple_temperature_chart_card", - "simple_temperature_chart_card_with_background" + "simple_temperature_chart_card_with_background", + "humidity_card", + "humidity_card_with_background", + "horizontal_humidity_card", + "horizontal_humidity_card_with_background", + "humidity_chart_card", + "humidity_chart_card_with_background", + "simple_humidity_chart_card", + "simple_humidity_chart_card_with_background", + "humidity_progress_bar", + "humidity_progress_bar_with_background" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json b/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json new file mode 100644 index 0000000000..105929125d --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_humidity_card", + "name": "Horizontal humidity card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAnFBMVEUAAADf39/f39/g4ODg4OD////k5OQjTMfg4ODz8/M+Ys7k6fjOzs51j9zIyMjy9PusrKz5+fm2trbb29vCwsKQkJCRpeMwV8usvOq8vLw9PT3n5+eesefW3fWRpuODm+DV1dVYWFhMbdHI0vF0dHS6x+1aedVmZmZohNnW3fTt7e2CgoJKSkpaeNUxV8ovLy8hISG6x+6enp6dnZ2UGhvnAAAABXRSTlMAIETfv0i0+14AAANBSURBVHja7dp5b9owHMZxxvrkh+OcJOSA0HCUY4WtO97/e5sdygCpg2orbVo9nz+Qa0uVvzKOUEuHiIiIiIiIiIiIiIiIiIiIiIiIiIiI6DV9evc6Vvez8971PndNhxPj3VNOt3Oj8AHEN50ePoQeQ1qGIW3DkLZhSNswpG2eDqlmIY5EDiYljmwABFEQoT2f054MuRVxNQ6mAaI7peDAaV4RAU40mATBVjlQ16oJq6zQsOZVttBH0/psyHHHacn0Z7C5C+4wdYab4Wo1xRCb1XAQDQbD/oPaRHhhx9v4AsDfjyztujP58pyQW2nMwkPI3WD1GGIOAt9NyAMiE+JMMfg5dHANWmQ+zsS1G3LnY1+WaGTfQri+6ZlfCBnLo/rkrXUaoob7kGC4wlUUsgaQi8ZM5kAoEu5CTNrSR+1eOhFX9uand2S7ejicyGC1NSFqW2Ia4SoKWTYhIYrCJoigUYnWbq1FXwgpRPwql3wt4uKUeuIH5WwVriJ0pdK1+Pt97UfhzF5g18eFENeW+/kYM3skl/3q40rGxzdV54cjGI9RufpCyBcRuV3Mxs2Vr/GGQlfWmSu3uw5XKhzovBhnmT4XMhcjtx2GjzdUid/ckfkuKsMR39f5V/MQPhOiHzvWVf7GJ7KWwm7Zvoaz045CdP0NcOszITD7X5jzsL9Cfpxe7FPqHqeUwkvypW6u7A/bVJ++6TL4zUP4XEgm4tb2nriHp1Z/F6Nwn6ARx4h7np3oIQYwikaIk2S3YCZeImku4mdLu4najKwFdhZmrvqmdV6cCwld2SuOQiYTLwkCz4xSpElaxv3Um0wCr7z3yhjwRqosEyivWfCCEv9vYXfyVQNL2cmOt7k0a+G5EOh9SYXjEK+vAm/k7UJGk8SMzdwo8dKgCekliQkJ+qNAmdxU4QWEOsRfaX3ps1ZYzERyf4w/Ii9Jvf4kSJU9Ea9M0r7qB56Zuy9HgQcbEtsTGZWRXZikKV7F+ZDLkhH+bhIkeI42hMTxuUWF52hFSBsxpG0Y0jYMaRuGtE2vc/MB/s0OqJtO12nPH3D/Wex07Vc4es5797n7kb5UQ0RERERERERERERERERERERERERERPRKfgPNbdZin3BhXgAAAABJRU5ErkJggg==", + "description": "Displays a latest humidity telemetry data in a horizontal layout.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:water-percent\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal humidity card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json new file mode 100644 index 0000000000..14882ac7e6 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_humidity_card_with_background", + "name": "Horizontal humidity card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest humidity telemetry data in a horizontal layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:water-percent\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal humidity card with background\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_card.json b/application/src/main/data/json/system/widget_types/humidity_card.json new file mode 100644 index 0000000000..bf034c0bbf --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "humidity_card", + "name": "Humidity card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest humidity telemetry data in a box layout.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:water-percent\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Humidity card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_card_with_background.json b/application/src/main/data/json/system/widget_types/humidity_card_with_background.json new file mode 100644 index 0000000000..bd7c696405 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "humidity_card_with_background", + "name": "Humidity card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest humidity telemetry data in a box layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:water-percent\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Humidity card with background\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_chart_card.json b/application/src/main/data/json/system/widget_types/humidity_chart_card.json new file mode 100644 index 0000000000..3cfeaa2c90 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "humidity_chart_card", + "name": "Humidity chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a humidity data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json new file mode 100644 index 0000000000..571f299340 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "humidity_chart_card_with_background", + "name": "Humidity chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a humidity data as a combination of the latest and aggregated values with background. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_progress_bar.json b/application/src/main/data/json/system/widget_types/humidity_progress_bar.json new file mode 100644 index 0000000000..12b81e5be7 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_progress_bar.json @@ -0,0 +1,29 @@ +{ + "fqn": "humidity_progress_bar", + "name": "Humidity progress bar", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAn1BMVEXg4ODf39/g4ODg4OAAAAD///8jTMfg4OD29vYhISHHx8fj4+M9PT10dHSQkJDx8fHk6fitra3I0vG6urpYWFjy9Pvv7++svOo+Ys5aedWGhoZ1j9y6x+7V1dWpqamenp6Xl5eCgoIvLy+Dmt9LbdEwV8vX3vSRpeOesefLy8tmZmbCwsJohNmOjo6RpuPY2Nh+fn7l5eVXdtJKSkrm5uZgoBxmAAAABXRSTlPvIL+vAC9A4IoAAAQhSURBVHja7M/BEQBABAPAOIynn/5LvTbCZDtYhD3Udm4Bw+R6DYN3HjAPlSfgSqQUIaMIG0XYKMJGETaKsFGEjSKf3TrWcRAGoihaveJ5xjNCoWUtu3Sb//+3JVgrlA2KqYBIuUg2yNURU/hqvYHcBl+37czQigyQGHBCfYhSMDe2bSsnfYUk5pltgn1dCYJpwgpB8Payq3MgwSZgsgCxEHKesCyAJQCS8xAZlnO7M/5MdgOQzNHpeIhxAAYaApWFrI8lAFRACh9PWM61UKuzAEJFp+MgNc7pP4ggtyU2yEiDKBukjda4fGV0Og6ij/gMiUBgBYRjg7AAiE+QRFt+ZK8zR6tB4gqZ9xeIU513vO9qEKe+QDAy8QedzoAkJiBtQqB0oD5DbizdyToFEqgp6TbEqINxhdQb4IUjOp0CgZGlbkOQSc1/kEkXQjx0slZIPxd/cwasiS8Qwc6ufPuVwIpenwAZWQS9PgESBke3T4Ds6Av5Qn7Zn2MUAGEgAIJVUocDwWBrxMr/P09DsI3tCjs/mL8wQmOExgiNERojNEZojNAYoTFCY4TGCI0RGiM0RmiM0BihMUJjhOYjckSU9FoiYklQ08jZ8qOOSqm526CVWeTKQyv9seZhT0iTSLnZL3sVh2EgCFczpMtiEJKwO8s/hau8/8Od8JokBG6PwIE3RB8ujCt/jGYlkewQRjIDyOQYMFedCI8YIgPZAwgTJ2BWHf3oEUMkkhGaxS6wHDFleMQQ6cgRlcQEBJFw/+gRQ6QaTMNe+QV3erLDjrPpZYlIIqdJS/HozXYYlTzDEZZI0Pk7xWe1SXTdZXQbxE9fLJFSw4hrIteniAaoSI85ox/gBXtqLQBCTSFoQup0vA/jGB1NYkMkk4LKeozhUNRMkWWVLHCDLRI0Gc1hU48HfewWN2vLENmOSdtrMcbXHUSKpFi8HFjsjiQ9a6WwbyelUwQ7SeKCwUtNDBH0PBgA4QMNYV0QR0Qv+7wlgphYyR1eRQ5C2pKXvv95Q5wDDMTNQeVb7uyfQxPxRhPxRhPxRhPxRhPxRhPxxheISOYZlPli8r5I4TncLjZvi/AsLpXrr8/7IpnnUOrv/msiUngGN+2IylxfXipfPLU+jCbijSby094dqzgMwwAYdtr+1MtxBIMGQVKtwYSkcO//bFdK5kK6WE31g3d9eNAobwXEWy8gdbZC43IdATEz2QbaDxEVbKFpWXsFxspkLJpllf2Q4Qal+ZeIAirkldrDOO2HTKMbyM/zlRIQLxAVWKlvQmTN3AaatkFsYTAWA/3bD6HobLRtg9zV9A79PBfegJAzXpJtoO/e7J9VQLwVEG8FxFsB8VZAvBUQbwXEWwHxVkC8FRBvHQiSOETXdDrA6Wn4PacuHeD4tDwYl+58/fTSqbv8A8IwqxFwwnsYAAAAAElFTkSuQmCC", + "description": "Displays humidity reading as a horizontal progress bar. Allows to configure value range, bar colors, and other settings.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 2, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'humidity', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-progress-bar-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-progress-bar-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":0,\"tickMax\":100,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.04)\"},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "progress", + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json b/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json new file mode 100644 index 0000000000..e5b42cce70 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "humidity_progress_bar_with_background", + "name": "Humidity progress bar with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays humidity reading as a horizontal progress bar with background. Allows to configure value range, bar colors, and other settings.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 2, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'humidity', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-progress-bar-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-progress-bar-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":0,\"tickMax\":100,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.04)\"},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "progress", + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_humidity_chart_card.json b/application/src/main/data/json/system/widget_types/simple_humidity_chart_card.json new file mode 100644 index 0000000000..e3870774cd --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_humidity_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_humidity_chart_card", + "name": "Simple humidity chart card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAhFBMVEUAAADg4ODf39/g4ODg4OD////g4OAhISEjTMfj4+PHx8c8PDysrKzx8fGQkJAvLy/k6fhYWFg+Ys50dHSsvOqenp6CgoLV1dXy9Pt1j9wwV8tohNlmZmZKSkqDmt9aedXI0vGRpeO5ublMbtK6urq6x+6eseeRpuNaeNXW3fXW3vTW3fS+UfxxAAAABXRSTlMA7yC/r1EOHTEAAAR+SURBVHja7M9JAcAgDAAwytEf/u0OGdAlDtIAAAAAAAB+p4/I181+HrHX83b0Ngs8zmS0XCVElUiKXEbkNh/79bIiNwxEYXh1OFSVLohG1ka9MX7/Z8zIYdJm3EFhIMJm9CPjonYfeGFNyNWakKs1IVdrQq7WD4Dc7JryV4g8Aw5pbrsgOCV1JyvF14LB9SFi5FESDIBScapU+YQkRU4YWR/y5Ef5DcQJvPMfxznxbgPEeXwMjuKdaI2uLdrTaQxk4Z6eIXQQqtCS2TMxQSlIMUWK0AVj8sxwFHQaAhFajrEyvSBsHSAZGwuW2CDKDdsO2cEptdNrCGThA6kUsvyBRFXNB4hrAgS2lyOgL0iObeo0BlJJKyWS6+nTeg/xR4iPlR6dxkAejKU8VlJPkPhA/grxDAgvCBIrug2BKG2LS6HhBMlk+gpBaEv5vSSgdOg2BILKPYdzXt4uj9MWMaY+BAtJW/GtFlvQbRQEEME3C8Hj35t/vxNy7Sbkak3I1ZqQqzUhV2tC/k+aQ8h6e0iO3LNwa4g8mZwAfq00uS9ELK6f82omt4VYlKPK/E0hv9gxtx1VYSgMX630Ly20tIgcRtFxO8f3f7/NdKYeCFqICcGE78YGuFhf1gmRTF5//kieVESkdIVV/ClFZPdDP1f2KUXEhjokLHoKkbX8F/V2iCdW6ROI/K4+IX3QQhD1pGQ+ItHK5iveE2Mq+VpuWB7/rcI1UU9K5iLCU8aUYszyrkfiDyKXMldKBgbAAyJ6V1ycdc+dIFypJG5/8s4bB2f2dHxhrWvOqZeN4I+KvFcAGn0+m8xrNADeBnkIH8f6qkhifz34aZarqydjHo8V2QLmA6j0+YwjOUpsdwYF0U4HRBJ2iuL1cijlviHCrJWfB3Fk1U/ybDRGRAMlka6wJcqAvTs35DCHn2tZezCh1WAviiS9qPxk1BuxsCu5ai2U+xVMyOEiR+CLiBociEqYvxxdi7xDj9jVryw5FxyNoZsJ2arkfLCIi7LGB1G2d92x9yJNpVuro0ZJ90nFdZ1Z7uJQIxq4vzci6+dgUKRwRaWBjDwGNTkymAMMNSaQEM5kp2NYaq1iKaeH4VZshjV7VsE0FWryvAHf/l5d7wvXJXexrBMxz1MhfIU8ShwPEylqtFSnYD9dx5/RpqRwq09AqLQMTLYrgczHjQNdUkJ/1k2tA60+If0iGaBduNXJo6ALdthrVLWpbpsEZ9MUIm5ceR/n0elsY2iLr9ZnSzfIgwmZQsTvjjcnUhw6Hm6FNCC6PYLz8NKbQMQZvP9mwq3FTgW5+EsU9H0jI9FmIo9wsx+AygA4/kh5Si+y1UQZ6mONrHfIM/FK0xAev6UB8LFzK70r4nDX9z0DPnHv7tMR/j+iC7pL0fdAJEav7jl+jecpExENY84iK6WGN/mcRV7siOaYs8gYFpFF5FlYRObGIjI3FpG5sYjMjUXkfzv3UQAACANBMLT88G8XAwigzDg4AbenMeQ0GWU8IaNd9mXdm/2dCFLUnrcrrQYAAAAAAMBvFtRAowTiuzzYAAAAAElFTkSuQmCC", + "description": "Displays historical humidity values as a simplified chart. Optionally may display the corresponding latest humidity value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'humidity', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#D81838\"},{\"from\":20,\"to\":40,\"color\":\"#FFA600\"},{\"from\":40,\"to\":60,\"color\":\"#5B7EE6\"},{\"from\":60,\"to\":80,\"color\":\"#305AD7\"},{\"from\":80,\"to\":100,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"%\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_humidity_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/simple_humidity_chart_card_with_background.json new file mode 100644 index 0000000000..bd2a4181b4 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_humidity_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_humidity_chart_card_with_background", + "name": "Simple humidity chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays historical humidity values as a simplified chart with background. Optionally may display the corresponding latest humidity value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'humidity', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Humidity\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"%\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "humidity" + ] +} \ No newline at end of file From 049f40a62e4cba6ffcd863eaada4a0ad6a7f360d Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 19 Oct 2023 14:00:04 +0300 Subject: [PATCH 216/267] Clear interruption status after exiting consumer while loop --- .../service/queue/ruleengine/TbQueueConsumerTask.java | 7 ++++--- .../ruleengine/TbRuleEngineQueueConsumerManager.java | 8 ++++++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java index 2e3a4676e8..9c0df63ad5 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java @@ -41,8 +41,8 @@ public class TbQueueConsumerTask { private CountDownLatch completionLatch; public void setTask(Future task) { - this.task = task; this.completionLatch = new CountDownLatch(1); + this.task = task; } public void subscribe(Set partitions) { @@ -63,14 +63,14 @@ public class TbQueueConsumerTask { if (isRunning()) { try { if (!completionLatch.await(30, TimeUnit.SECONDS)) { + task = null; throw new IllegalStateException("timeout of 30 seconds expired"); } + log.trace("[{}] Awaited finish", key); } catch (Exception e) { log.warn("[{}] Failed to await for consumer to stop", key, e); } - task = null; } - log.trace("[{}] Awaited finish", key); } public boolean isRunning() { @@ -79,6 +79,7 @@ public class TbQueueConsumerTask { public void finished() { completionLatch.countDown(); + task = null; } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java index 3a7b2f15d8..71a7c45d45 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java @@ -237,7 +237,11 @@ public class TbRuleEngineQueueConsumerManager { log.info("[{}] Launching consumer", consumerTask.getKey()); Future consumerLoop = ctx.getConsumersExecutor().submit(() -> { ThingsBoardThreadFactory.updateCurrentThreadName(consumerTask.getKey().toString()); - consumerLoop(consumerTask.getConsumer()); + try { + consumerLoop(consumerTask.getConsumer()); + } catch (Throwable e) { + log.error("Failure in consumer loop", e); + } consumerTask.finished(); }); consumerTask.setTask(consumerLoop); @@ -262,7 +266,7 @@ public class TbRuleEngineQueueConsumerManager { } } } - if (consumer.isStopped()) { + if (Thread.interrupted() || consumer.isStopped()) { consumer.unsubscribe(); } log.info("Rule Engine consumer stopped"); From ec907c66bad9387c6d8aac5b3970a037ea91a7bd Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 15:05:01 +0300 Subject: [PATCH 217/267] UI: Fix progress bar widget percent value calculation. --- .../widget/lib/cards/progress-bar-widget.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts index fe1ac58ab4..22d3cb6f4d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts @@ -181,7 +181,9 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI this.valueColor.update(this.value); this.barColor.update(this.value); const range = this.settings.tickMax - this.settings.tickMin; - this.barWidth = `${(this.value / range) * 100}%`; + let barWidthValue = ((this.value - this.settings.tickMin) / range) * 100; + barWidthValue = Math.max(0, Math.min(100, barWidthValue)); + this.barWidth = `${barWidthValue}%`; this.cd.detectChanges(); } From 357428749905cca6d8aca705dcdbe675fe93eb44 Mon Sep 17 00:00:00 2001 From: rusikv Date: Thu, 19 Oct 2023 15:05:25 +0300 Subject: [PATCH 218/267] UI: fix for help icon in custom date of card widgets --- .../common/date-format-settings-panel.component.html | 2 +- .../common/date-format-settings-panel.component.scss | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html index 3a2d9f78b9..279b48fb3a 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.html @@ -21,7 +21,7 @@
date.format
-
+
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss index 784b4fbeb4..7ca3237b5d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/date-format-settings-panel.component.scss @@ -48,9 +48,12 @@ } .mat-mdc-form-field.tb-date-format-input { .mat-mdc-text-field-wrapper.mdc-text-field--outlined { - .mat-mdc-form-field-icon-suffix { - display: flex; - align-items: center; + .mat-mdc-form-field-flex { + .mat-mdc-form-field-icon-suffix { + display: flex; + align-items: center; + line-height: normal; + } } } } From b258a11ce35e47272dde125c5b02a02c60748f9b Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 15:23:37 +0300 Subject: [PATCH 219/267] UI: Outdoor Environment: Pressure widgets. --- .../widget_bundles/outdoor_environment.json | 12 ++++++- .../horizontal_pressure_card.json | 28 +++++++++++++++++ ...izontal_pressure_card_with_background.json | 28 +++++++++++++++++ ...humidity_progress_bar_with_background.json | 2 +- .../system/widget_types/pressure_card.json | 28 +++++++++++++++++ .../pressure_card_with_background.json | 28 +++++++++++++++++ .../widget_types/pressure_chart_card.json | 31 +++++++++++++++++++ .../pressure_chart_card_with_background.json | 31 +++++++++++++++++++ .../widget_types/pressure_progress_bar.json | 29 +++++++++++++++++ ...pressure_progress_bar_with_background.json | 29 +++++++++++++++++ .../simple_pressure_chart_card.json | 31 +++++++++++++++++++ ...e_pressure_chart_card_with_background.json | 31 +++++++++++++++++++ 12 files changed, 306 insertions(+), 2 deletions(-) create mode 100644 application/src/main/data/json/system/widget_types/horizontal_pressure_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_card.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_progress_bar.json create mode 100644 application/src/main/data/json/system/widget_types/pressure_progress_bar_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_pressure_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_pressure_chart_card_with_background.json diff --git a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json index 71c148d22c..298437107d 100644 --- a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json +++ b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json @@ -25,6 +25,16 @@ "simple_humidity_chart_card", "simple_humidity_chart_card_with_background", "humidity_progress_bar", - "humidity_progress_bar_with_background" + "humidity_progress_bar_with_background", + "pressure_card", + "pressure_card_with_background", + "horizontal_pressure_card", + "horizontal_pressure_card_with_background", + "pressure_chart_card", + "pressure_chart_card_with_background", + "simple_pressure_chart_card", + "simple_pressure_chart_card_with_background", + "pressure_progress_bar", + "pressure_progress_bar_with_background" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json b/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json new file mode 100644 index 0000000000..c96757cebf --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_pressure_card", + "name": "Horizontal pressure card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAolBMVEUAAADf39/f39/g4ODg4ODf39/////k5OTYGDjg4ODri5v64ub1xc3nboLdNVHwqLT98fPOzs5YWFjz8/O3t7faJkXx8fH5+fnb29vCwsK8vLziUmnV1dXHx8fkYHbn5+f409rIyMjzt8HpfY9mZmarq6t0dHTiUmrfQ13umqiQkJCCgoJKSko6Ojrt7e3tmajsi5z39/faJkTgRF3pfY4hISGGGYADAAAABnRSTlMAIEDfv1C6kOEmAAADqUlEQVR42u3ai1LaQBiGYar2z89uzgdIYgKEcBJBrW3v/9a6WUCgUiTMlAnM90hCTHCyr7Aggy0AAAAAAAAAAAAAAAAAAAAAAAAAAACAS/p29XTG3b1x7dr331WH8YOuXmDctR4CugE/HlptuglthDQMQpoGIU2DkKY5HOJKujaHQyy+upJDIc6bxaagrfF8blDDHQqxOVJfQ/rgj/NlZnQ6VOUYHb2otVoZ1eUs5vrqVXycaOCYq31CmLQmWGx+wFGGgzoh0mZmQVt+TqPQX+TPI7/zPFlk88kyn+SGb/xeGP7o+YyKMmKqvLFiS50xZbY2Z2fb/TvEYs2Wp4RsSwTt8Be+T35mLMejsT9JO3O16BCf5qPxkmpyZ6yQItk2ByVPq46ILaca5CNbcjBj8Tmk5zivM5VYY7LLJ9rl59XKMJZ52MlzP83y0XgS6pDnSZ5TTdIWziqk5FJ1RazGZrNDml2NdMj2R4g7HEodopMidlaPQnk8RIodw/0Q0g+t0cKYj/xwvBxVIcZiNKH65CrkUc/EGQ/UyC2S27GZPN2E9Gzmd3MToq/klJW3oyEm77DoL529Zbvv/BBzvS65F20mgCvNn+xsQlg4PZ5+hDzyE/W4NJ2I5bEQ19whqZ7zQ9TClrB5uh68Gu0m5JcaFHMVYpnm0OJIkhAuqRrnjHvkAiFCz5aBfvq1ondzd7KvQrSouoX7Wlo2O3XniHKBkGrL2gzO5NnnkJ7jOLrviaPZowqp+6yl/KcQPXA92fUDRa2HrjMkhflziKAVl1luo794HXmjHQEdELz8vSOoHfLKvWrbrram+rzS5Xc1ygHb/w6R/K6jnVNe2fdKQh2jLi8xad0uddtetaNNXfV9f9ynbhyvDqgdwYkhrq2nuFhv/WSrGqAtyojF4RCtuu2UvwxxV39rOXshWebFReGprYSSOEm7YeJlWeGlL16qRu71gzSNKfD0Aa9ITwvRv7Oo1Fs9Zi5ddXpVwdETHQkZ2MxTi8ujIYoQFps9dz/EC4PC63urkH4Wq221rx97SaFD2nGsQoqwXwQqNwnoRK50P21JSV+Q8qz3I2MvTrwwK5IgVCFeGidhEBae2veS9gsVp0K61T3ST8fVgSxJ6AyXf4cY9+nfsiKmy9MhtXW7xw4GdIpGhDQRQpoGIU2DkKZBSNO0Ww838DE7UfDQujNu4IP2H8Zdq/X9vm1cu/u7W/qnGgAAAAAAAAAAAAAAAAAAAAAAAAAAAIAL+QMW1wDljmkjjQAAAABJRU5ErkJggg==", + "description": "Displays a latest pressure telemetry data in a horizontal layout.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"compress\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal pressure card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json new file mode 100644 index 0000000000..58d63484ae --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "horizontal_pressure_card_with_background", + "name": "Horizontal pressure card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest pressure telemetry data in a horizontal layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"compress\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal pressure card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json b/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json index e5b42cce70..697d527eea 100644 --- a/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json +++ b/application/src/main/data/json/system/widget_types/humidity_progress_bar_with_background.json @@ -17,7 +17,7 @@ "settingsDirective": "tb-progress-bar-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-progress-bar-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":0,\"tickMax\":100,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.04)\"},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"humidity\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":0,\"tickMax\":100,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":20,\"color\":\"#DE2343\"},{\"from\":20,\"to\":40,\"color\":\"#F89E0D\"},{\"from\":40,\"to\":60,\"color\":\"#5579E5\"},{\"from\":60,\"to\":80,\"color\":\"#2B54CE\"},{\"from\":80,\"to\":100,\"color\":\"#224AC2\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.1)\"},\"title\":\"Humidity\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"%\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:water-percent\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" }, "externalId": null, "tags": [ diff --git a/application/src/main/data/json/system/widget_types/pressure_card.json b/application/src/main/data/json/system/widget_types/pressure_card.json new file mode 100644 index 0000000000..db557728f5 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_card.json @@ -0,0 +1,28 @@ +{ + "fqn": "pressure_card", + "name": "Pressure card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest pressure telemetry data in a box layout.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"compress\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Pressure card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/pressure_card_with_background.json b/application/src/main/data/json/system/widget_types/pressure_card_with_background.json new file mode 100644 index 0000000000..b7d75d7426 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_card_with_background.json @@ -0,0 +1,28 @@ +{ + "fqn": "pressure_card_with_background", + "name": "Pressure card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest pressure telemetry data in a box layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"compress\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Pressure card with background\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/pressure_chart_card.json b/application/src/main/data/json/system/widget_types/pressure_chart_card.json new file mode 100644 index 0000000000..055e80730d --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "pressure_chart_card", + "name": "Pressure chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a pressure data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json new file mode 100644 index 0000000000..b0477cc2e1 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "pressure_chart_card_with_background", + "name": "Pressure chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a pressure data as a combination of the latest and aggregated values with background. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa');\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"hPa\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/pressure_progress_bar.json b/application/src/main/data/json/system/widget_types/pressure_progress_bar.json new file mode 100644 index 0000000000..1c7c5fce59 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_progress_bar.json @@ -0,0 +1,29 @@ +{ + "fqn": "pressure_progress_bar", + "name": "Pressure progress bar", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays pressure reading as a horizontal progress bar. Allows to configure value range, bar colors, and other settings.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 2, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-progress-bar-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-progress-bar-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":870,\"tickMax\":1085,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.04)\"},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "progress", + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/pressure_progress_bar_with_background.json b/application/src/main/data/json/system/widget_types/pressure_progress_bar_with_background.json new file mode 100644 index 0000000000..ac4fd7fd6b --- /dev/null +++ b/application/src/main/data/json/system/widget_types/pressure_progress_bar_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "pressure_progress_bar_with_background", + "name": "Pressure progress bar with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays pressure reading as a horizontal progress bar with background. Allows to configure value range, bar colors, and other settings.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 2, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.progressBarWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.progressBarWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '280px',\n previewHeight: '180px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-progress-bar-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-progress-bar-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"tickMin\":870,\"tickMax\":1085,\"showTicks\":true,\"ticksFont\":{\"family\":\"Roboto\",\"size\":11,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"ticksColor\":\"rgba(0,0,0,0.54)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"barColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}]},\"barBackground\":\"rgba(0, 0, 0, 0.1)\"},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"hPa\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"18px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "progress", + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_pressure_chart_card.json b/application/src/main/data/json/system/widget_types/simple_pressure_chart_card.json new file mode 100644 index 0000000000..5813b377cd --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_pressure_chart_card.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_pressure_chart_card", + "name": "Simple pressure chart card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAgVBMVEUAAADg4ODf39/g4ODg4OD////g4ODYGDghISHj4+M8PDziUmnHx8eQkJDsi5tYWFjx8fH1xc3dNVH64uZ0dHQvLy/nb4LwqbRKSkraJkSenp6CgoL98fKsrKzumqj409rV1dXzt8HpfY+rq6tmZmbkYHbgRF26urq5ubnfQ1398fNuhph/AAAABXRSTlMA7yC/r1EOHTEAAAS8SURBVHja7M9JAcAgDAAwytE3/tUOGdAlDtIAAAAAAAB+p4/I181+HrHX83b0Ngs8zmS0XCVElUiKXEbkNh87dqzqMAxDYXg6IAkJebDBJBgMDSTv/4Q3bUNDB8OdgkP9D0YaPzAkeEB6a0B6a0B6a0B66wcgy4o71YJUz7OHc1czmxj91oKwEBnOLMUopOi2FgQsBpyZAHDHVreKUAoD0LIC+7LyfgRwCVz4Nay4tDakquqqe/wFWTI8pYklOSnmFMVR05KFmRRKrJSEV8qScWVtSJSj7bxapRgZ3ANmCfAFMkPjSxj1A5kAiXiuF9aGFDuqHwiJZAM8Ap7cRWDkM6OKRMUH8hyzOxkurA2Z4pF+XS28IYuoagX4IQJgi6RfEFNVxjW1ISem4uwLMlGFPgJN+xQWR0hToBn2hsAzB+sHYpRqA4KZKG0wEjKwpOQMI/IDwrLP3UA0SRa0Cvw+A/b4WPCJL2e0IWAvPX/I/w9Bvdeb8A/8/d6sAemtAemtAemtAemtAemtAemtriHmRCny3SGcyWeLQo+bQ5weh0dvDfljx9yWk4WBAHy1syGRBIKcEX7w0Nr3f8CfZWOpI6XWC0Y6fhdkXaKz3yQbGN9EwUEgzapFDhIchfDWLBJvwREIf8UiG/E+dku2QhEv4LEUHPDe2qxNpIiFOHgUZQYY3lsrE9kJs/NjGQC8Xz09jHx6kX+74su2kdnQHdIvYy593FvPLRIY0WO8zwXZD3JGxGUAcLW3nltkK3wv2McZMJmEbzCx97BI1QAT1rod003aXNJ1CA6FCTiqcKC574gtaHgXb+7jHr7Bi6VHQymlKbzfiIQq11yYwh7rCtM5oh58LKdvREJkbAo/4rsjNja8PnKml6QwWyPiQ3+Ru3tFoi5HVzB0mOvaoq24YDwnLc3I8VT36byaEDkrpSxiDT9hzEWooOtsI3ilkZkfUCRFGdwhwsUoyyIfiGl/zbFmqRCcHplFdPNWJKLvnUlynkCULsiE3GbCwJ34Qnr3rUhdgULt6qJ6EjyOdVM6bWkgWycSJkqlowi0iA1ApY+UnmYzHqp7I80e7mYjs7ub3YnUmNOg8UyxqtKx8Qez1k22SKSjSIMYQsRpBRPwW8iDBMFvRTRaN1DqRL1jIyCasD3h6TIZddRYVKNI3Y8kWFHUzrTIwzwuckZUtc4p5OJRVeDio1s9EmnDsNVIqTZteAPOtcjyIhYVN0FIqTo5InZfj98UkW47FO+wVGsSmWuR5UU45QY+hNMJkWOSJN0gGykkpkW2MSwoknKzd6gmROCIyYRIBBcsnkL+qakFKZcUaaguV2nCxw8tw9F2rjfmRD54F06KbGIZLCbCZXeDTst9DKCp0g7zaEincyIRoqbMhMheZB4sKlIj2pN7FHT9eBrKiiyHFma3luJZdPeaQmQBLCsCqUXMuwoITXFNUZRgH+pqToRn5brD8807xiGAJUSuiaLqS3wTzlIN373x2MLIev/E9ofz6g+IHHy6/gER4iXyElkLL5Fn4yXybLxEno2XyLPxEvnfzn0TAAACQRB80tf4V4sCesKMgxNwexpDTpNRxhMy2l33io3Z34kgRe15u9JqAAAAAAAA/GYBBOmvbsxu/swAAAAASUVORK5CYII=", + "description": "Displays historical pressure values as a simplified chart. Optionally may display the corresponding latest pressure value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'pressure', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#D81838\"},{\"from\":1000,\"to\":1020,\"color\":\"#80C32C\"},{\"from\":1020,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"hPa\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_pressure_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/simple_pressure_chart_card_with_background.json new file mode 100644 index 0000000000..817dd610e2 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_pressure_chart_card_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "simple_pressure_chart_card_with_background", + "name": "Simple pressure chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays historical pressure values as a simplified chart with background. Optionally may display the corresponding latest pressure value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'pressure', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Pressure\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 80 - 40;\\nif (value < 980) {\\n\\tvalue = 980;\\n} else if (value > 1040) {\\n\\tvalue = 1040;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":null,\"to\":1000,\"color\":\"#DE2343\"},{\"from\":1000,\"to\":1020,\"color\":\"#7CC322\"},{\"from\":1020,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Pressure\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"compress\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":0,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"hPa\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "pressure" + ] +} \ No newline at end of file From 2d1640a0025798cafb3a967562c3773978b936d5 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 19 Oct 2023 15:29:46 +0300 Subject: [PATCH 220/267] Don't interrupt consumer loop task on stop --- .../queue/ruleengine/TbQueueConsumerTask.java | 23 ++++--------------- .../TbRuleEngineQueueConsumerManager.java | 18 ++------------- 2 files changed, 6 insertions(+), 35 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java index 9c0df63ad5..59d55285f0 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbQueueConsumerTask.java @@ -17,6 +17,7 @@ package org.thingsboard.server.service.queue.ruleengine; import lombok.Getter; import lombok.RequiredArgsConstructor; +import lombok.Setter; import lombok.extern.slf4j.Slf4j; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.gen.transport.TransportProtos; @@ -24,7 +25,6 @@ import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import java.util.Set; -import java.util.concurrent.CountDownLatch; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; @@ -37,13 +37,8 @@ public class TbQueueConsumerTask { @Getter private final TbQueueConsumer> consumer; + @Setter private Future task; - private CountDownLatch completionLatch; - - public void setTask(Future task) { - this.completionLatch = new CountDownLatch(1); - this.task = task; - } public void subscribe(Set partitions) { log.trace("[{}] Subscribing to partitions: {}", key, partitions); @@ -53,23 +48,18 @@ public class TbQueueConsumerTask { public void initiateStop() { log.debug("[{}] Initiating stop", key); consumer.stop(); - if (isRunning()) { - task.cancel(true); - } } public void awaitCompletion() { log.trace("[{}] Awaiting finish", key); if (isRunning()) { try { - if (!completionLatch.await(30, TimeUnit.SECONDS)) { - task = null; - throw new IllegalStateException("timeout of 30 seconds expired"); - } + task.get(30, TimeUnit.SECONDS); log.trace("[{}] Awaited finish", key); } catch (Exception e) { log.warn("[{}] Failed to await for consumer to stop", key, e); } + task = null; } } @@ -77,9 +67,4 @@ public class TbQueueConsumerTask { return task != null; } - public void finished() { - completionLatch.countDown(); - task = null; - } - } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java index 71a7c45d45..5a59cb124e 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManager.java @@ -242,7 +242,6 @@ public class TbRuleEngineQueueConsumerManager { } catch (Throwable e) { log.error("Failure in consumer loop", e); } - consumerTask.finished(); }); consumerTask.setTask(consumerLoop); } @@ -266,7 +265,7 @@ public class TbRuleEngineQueueConsumerManager { } } } - if (Thread.interrupted() || consumer.isStopped()) { + if (consumer.isStopped()) { consumer.unsubscribe(); } log.info("Rule Engine consumer stopped"); @@ -282,7 +281,7 @@ public class TbRuleEngineQueueConsumerManager { TbMsgPackProcessingContext packCtx = new TbMsgPackProcessingContext(queue.getName(), submitStrategy, ackStrategy.isSkipTimeoutMsgs()); submitStrategy.submitAttempt((id, msg) -> submitMessage(packCtx, id, msg)); - final boolean timeout = !awaitPackProcessing(packCtx, queue.getPackProcessingTimeout(), true); + final boolean timeout = !packCtx.await(queue.getPackProcessingTimeout(), TimeUnit.MILLISECONDS); TbRuleEngineProcessingResult result = new TbRuleEngineProcessingResult(queue.getName(), timeout, packCtx); if (timeout) { @@ -310,19 +309,6 @@ public class TbRuleEngineQueueConsumerManager { } } - private boolean awaitPackProcessing(TbMsgPackProcessingContext packCtx, long processingTimeout, boolean ignoreInterrupt) throws InterruptedException { - try { - return packCtx.await(processingTimeout, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - if (ignoreInterrupt) { - log.debug("Interrupt happened while waiting for pack processing, trying to await one more time"); - return awaitPackProcessing(packCtx, processingTimeout, false); - } else { - throw new RuntimeException("Failed to await pack processing due to thread interrupt", e); - } - } - } - private TbRuleEngineSubmitStrategy getSubmitStrategy(Queue queue) { return ctx.getSubmitStrategyFactory().newInstance(queue.getName(), queue.getSubmitStrategy()); } From 700aeba963983d01c8ccba2367d1d1fb71753ab7 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 16:17:06 +0300 Subject: [PATCH 221/267] UI: Improve min/max ticks formatting for value chart card widget. --- .../lib/cards/aggregated-value-card-widget.component.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts index 5380874811..b5b37df7f8 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts @@ -179,12 +179,10 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit } as TbFlotSettings; this.flot = new TbFlot(this.ctx, 'line', $(this.chartElement.nativeElement), settings); this.tickMin$ = this.flot.yMin$.pipe( - map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals), - (this.flotDataKey?.units || this.ctx.units)) + map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals)) )); this.tickMax$ = this.flot.yMax$.pipe( - map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals), - (this.flotDataKey?.units || this.ctx.units)) + map((value) => formatValue(value, (this.flotDataKey?.decimals || this.ctx.decimals)) )); } if (this.settings.autoScale && this.showValues) { From 6ff4f59e54dd2d1867955541b7a41e5ce874d72d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 16:49:47 +0300 Subject: [PATCH 222/267] UI: Fix default latest data keys units for value and chart card. --- .../data/json/system/widget_types/humidity_chart_card.json | 2 +- .../widget_types/humidity_chart_card_with_background.json | 2 +- .../data/json/system/widget_types/pressure_chart_card.json | 2 +- .../widget_types/pressure_chart_card_with_background.json | 2 +- .../json/system/widget_types/temperature_chart_card.json | 2 +- .../temperature_chart_card_with_background.json | 2 +- .../json/system/widget_types/value_and_chart_card.json | 2 +- .../cards/aggregated-value-card-basic-config.component.ts | 7 ++++--- 8 files changed, 11 insertions(+), 10 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/humidity_chart_card.json b/application/src/main/data/json/system/widget_types/humidity_chart_card.json index 3cfeaa2c90..9b59059ac2 100644 --- a/application/src/main/data/json/system/widget_types/humidity_chart_card.json +++ b/application/src/main/data/json/system/widget_types/humidity_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json index 571f299340..da6078bac5 100644 --- a/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/humidity_chart_card_with_background.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'humidity', label: 'Humidity', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '%', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'humidity', '%', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/pressure_chart_card.json b/application/src/main/data/json/system/widget_types/pressure_chart_card.json index 055e80730d..475189d065 100644 --- a/application/src/main/data/json/system/widget_types/pressure_chart_card.json +++ b/application/src/main/data/json/system/widget_types/pressure_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json index b0477cc2e1..63ba24c45e 100644 --- a/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/pressure_chart_card_with_background.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'pressure', label: 'Pressure', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'hPa', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'pressure', 'hPa', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/temperature_chart_card.json b/application/src/main/data/json/system/widget_types/temperature_chart_card.json index 4aecc59cdf..cebef335f5 100644 --- a/application/src/main/data/json/system/widget_types/temperature_chart_card.json +++ b/application/src/main/data/json/system/widget_types/temperature_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json index 9d5ebe5911..d5be89cb73 100644 --- a/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/temperature_chart_card_with_background.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'temperature', label: 'Temperature', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: '°C', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'temperature', '°C', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/application/src/main/data/json/system/widget_types/value_and_chart_card.json b/application/src/main/data/json/system/widget_types/value_and_chart_card.json index 10cfba9105..20b0245488 100644 --- a/application/src/main/data/json/system/widget_types/value_and_chart_card.json +++ b/application/src/main/data/json/system/widget_types/value_and_chart_card.json @@ -11,7 +11,7 @@ "resources": [], "templateHtml": "\n\n", "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'watermeter', label: 'Watermeter', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³');\n }\n };\n}\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'watermeter', label: 'Watermeter', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm³', decimals: 0 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³', 0);\n }\n };\n}\n", "settingsSchema": "{}", "dataKeySettingsSchema": "{}", "latestDataKeySettingsSchema": "{}", diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts index b8794b37fc..1956526ca0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/cards/aggregated-value-card-basic-config.component.ts @@ -117,10 +117,11 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo } protected defaultLatestDataKeys(configData: WidgetConfigComponentData): DataKey[] { - return this.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³'); + return this.createDefaultAggregatedValueLatestDataKeys(configData, 'watermeter', 'm³', 0); } - createDefaultAggregatedValueLatestDataKeys(configData: WidgetConfigComponentData, keyName: string, units): DataKey[] { + createDefaultAggregatedValueLatestDataKeys(configData: WidgetConfigComponentData, keyName: string, + units: string, decimals: number): DataKey[] { let centerKeySettings: AggregatedValueCardKeySettings = { position: AggregatedValueCardKeyPosition.center, font: { @@ -189,7 +190,7 @@ export class AggregatedValueCardBasicConfigComponent extends BasicWidgetConfigCo } return [ { - name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals: 0, + name: keyName, label: 'Latest', type: DataKeyType.timeseries, units, decimals, aggregationType: AggregationType.NONE, settings: centerKeySettings }, From 4587270e2229cc0535c9725b80514eb0901b3fa8 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 17:33:55 +0300 Subject: [PATCH 223/267] UI: Outdoor Environment: Wind Speed widgets. --- .../widget_bundles/outdoor_environment.json | 12 ++++++- .../widget_bundles/weather_widgets.json | 13 -------- .../horizontal_wind_speed_card.json | 29 +++++++++++++++++ ...ontal_wind_speed_card_with_background.json | 29 +++++++++++++++++ .../simple_wind_speed_chart_card.json | 32 +++++++++++++++++++ ...wind_speed_chart_card_with_background.json | 32 +++++++++++++++++++ .../wind_speed_and_direction.json | 10 +++--- ...d_speed_and_direction_with_background.json | 31 ++++++++++++++++++ .../system/widget_types/wind_speed_card.json | 29 +++++++++++++++++ .../wind_speed_card_with_background.json | 29 +++++++++++++++++ .../widget_types/wind_speed_chart_card.json | 32 +++++++++++++++++++ ...wind_speed_chart_card_with_background.json | 32 +++++++++++++++++++ 12 files changed, 292 insertions(+), 18 deletions(-) delete mode 100644 application/src/main/data/json/system/widget_bundles/weather_widgets.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_card.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/wind_speed_chart_card_with_background.json diff --git a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json index 298437107d..f2db1c22a3 100644 --- a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json +++ b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json @@ -35,6 +35,16 @@ "simple_pressure_chart_card", "simple_pressure_chart_card_with_background", "pressure_progress_bar", - "pressure_progress_bar_with_background" + "pressure_progress_bar_with_background", + "wind_speed_card", + "wind_speed_card_with_background", + "horizontal_wind_speed_card", + "horizontal_wind_speed_card_with_background", + "wind_speed_chart_card", + "wind_speed_chart_card_with_background", + "simple_wind_speed_chart_card", + "simple_wind_speed_chart_card_with_background", + "wind_speed_and_direction", + "wind_speed_and_direction_with_background" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_bundles/weather_widgets.json b/application/src/main/data/json/system/widget_bundles/weather_widgets.json deleted file mode 100644 index a38c139cf0..0000000000 --- a/application/src/main/data/json/system/widget_bundles/weather_widgets.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "widgetsBundle": { - "alias": "weather_widgets", - "title": "Weather widgets", - "image": null, - "description": null, - "externalId": null, - "name": "Weather widgets" - }, - "widgetTypeFqns": [ - "wind_speed_and_direction" - ] -} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json new file mode 100644 index 0000000000..94e177672f --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json @@ -0,0 +1,29 @@ +{ + "fqn": "horizontal_wind_speed_card", + "name": "Horizontal wind speed card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAn1BMVEUAAADg4ODf39/g4ODg4OD////g4OAjTMd1j9zk6fjx8fGtvOrOzs7IyMiRpePy9Pvj4+O3t7fI0vFaedU+Ys7z8/NYWFj5+fnb29swV8vCwsI8PDy8vLzn5+eesefV1dWenp6QkJCDmuCCgoJmZma6x+2rq6tohNkvLy90dHRLS0shISHW3fS6x+7W3fXU1NSRpuNMbtFMbdGsu+qtra1mE7QcAAAABXRSTlMA7yC/r1EOHTEAAAN3SURBVHja7dprU5tAGIbhJPpmOW2AcAgg4ZRzGrXa/v/f1neJLbY2FJypg5nnMgSy5MPeLMw4oyMAAAAAAAAAAAAAAAAAAAAAAAAAAAAA6G1yM55+drcT7hgb9OkZ48no9go6uORmNKWrML6WkClCBgYhQ4OQoUHI0FxtyIneMgpyUnKd0qCzkDenKB36Q5HTB2oPERW9tTdWIYUO9xgGdxlfeOwo3Tsy1Od6c9T+IKmfOSkPZs1uxu05XbYxO4VolGWbk02vHWQYGnfEP4e7rXNcq5CwcBzny+FopMew4LGVwSdlr4oqFqRooqb/qvB4Fpf5WqeQ+N4TLPZ2M3OuU60ow7JcqxBnW662pEKc7V3phLTahmWxXq23e7mmPitiPwlGiieyVyuyiYVoC9mI+44r4vH2IITnPQsxJyXfF3Jf/BZirIi+OEdauWEh89VBSnmgdY8Q3Z+ZLyHPvGvMvCxrQmzdtjcbnei0OVFN84npfJW7hJAQ30hXIbV9zq+XkDxc73moDMOVs18fHTfkWytUt9Z6L6kP/SVExGTTa2YTookqFiKeq9ukqsvUOdsT7Gu3EG22UyF/YfzcOaFRHzTbe0JsEfNcd/qFkHhm8kSezCyuZ2Oq969i9zDnz20hPj8jvi9E7O+qbGNTG6OkFh1DeBdrlS/8CyGz+ou6OvzGA5763k49J6a2aV+RSpuZDzr9Z00I2TpvfH3bQppDfqNM+Jq6yO0hH6IJaWbcJcQUOjHTV8/IwELmpppb1S3k2aMznVvMviEB/W3Q+HMgeF9IJnb87os5j/wr5HSe/JNvE83ErG+IW8fwy4iotljQYmqpgSktiGi5XdIiis4neCDoE2L7Qpt5wldJWnsIb3VrJTwz88X9O0Ly3IqktPgooSRK0oWbWHkurdSwUp65tQzSNKLAqk9YMu0RQronhPB0FVL9I8TfkWJX6pePjN4R8mi5gbSW1jlk+RjxMY8tIyuRdcg0ijhEuksZcG4SUB+2bp/31G7ePBY6h7eFzHV667sVJZabyyRQK2KlUeIGrrR4zEiX0iIVslArsky/qxN5ktBHUyG9RUu67FFG1MUQQhaLtpMBdTGIkCFCyNAgZGgQMjRXFDKmqzAd3VzHn6dvr+cfBkaT2+lnN76ZjAAAAAAAAAAAAAAAAAAAAAAAAAAAAACgrx9YOdsEpKcg1gAAAABJRU5ErkJggg==", + "description": "Displays a latest wind speed telemetry data in a horizontal layout.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:windsock\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal wind speed card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"m/s\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json new file mode 100644 index 0000000000..3b2c8cf8ff --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "horizontal_wind_speed_card_with_background", + "name": "Horizontal wind speed card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest wind speed telemetry data in a horizontal layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:windsock\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal wind speed card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"m/s\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card.json b/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card.json new file mode 100644 index 0000000000..ee1c935255 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card.json @@ -0,0 +1,32 @@ +{ + "fqn": "simple_wind_speed_chart_card", + "name": "Simple wind speed chart card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAgVBMVEUAAADg4ODf39/g4ODg4OD////h4eEjTMchISHHx8c8PDx0dHQvLy9YWFjx8fHI0vGQkJDk6fisrKxaeNWCgoJ1j9w+Ys7y9PtKSkqenp6tvOrV1dVaedW6urqRpeOfsecwV8tmZmbW3fSDmt+rq6tohNhMbtK6x+0xV8rw8PDW3vVvo8R5AAAABXRSTlMA7yC/r1EOHTEAAATVSURBVHja7M9JAcAgDAAwyvXEB/4NbjKgJA5SAAAAAAAAnlNbzNv1+j9ij+utqKWvkcBuZY4UIktkihxG5DQfu3Ww4kgIRWF4dS7n6lVEXCjiIpD3f8ZxqphM6GSgpxeJAX9EQd18FEJtyGptyGptyGptyGptyGo9hUjGl2LqQB6ANrSGu1w6ll58EvwzZjz0Aog6DI24zwpgFQgB5QmkMyTn4nIQdlpw9VKa4MwHKBlhaRqhqlkBaJYT4g2IbDFLHpidxzFnOW+974vQw3MkJpw1Qws2OhVhHlkNVGRWd95IbJjJ4QeKBSaIc8E6Emt9JyReWC43SGcPyZfBeEAq4DyqR7TzRqHzAuGAUueY8ugdEDysQN4FsU5Xfcr976Fl01xLxQEJx8J2e+yQqzMRKsCcGUKlBAtzCPWdjz3iS6EaImu5h9gN0gYQmW6QoaoIYc5dON4JeSjxAjiOe0ioIpYOputQXoUFjTJJkIZkgmuHXaALQZRXoFDuIeLo3AGJnuTcYCATcHXH4knrGI7V1oE8T/CnKBEQaoznQTw3b/NjL4BIwc8SKv63Jf+1YhJ8s7Uh329DNuRT2pDV2pDV2pDV2pDV2pAXpC0l/XxID/ydyx8OGUYrqTgyfTREjCVilkj9ZMgv9sx1V1EYCMC/hhluBVZoFREQ1kv2/R9wh1bkHAIH2E0IJH4JtIDE+dJpB9QlFwwh+XsW8aiNS3hk71fEpiO0xBTvV8Sl+IuUtzcRy/wNwTh0hjcO2fsSiYmJhR4EBzpCcnclEpPnXqkJWhy/hS7IE1sWsV3neL10kRBZun44Pm/fovLptGGRkDRhr3JYDhH534M6kf/PIkFdBsBkaEjhjSqyA/yIfM5ZYCk+n09Epy8Dojnb/ZCE9/a1rCUiKm/i1yKyLxIkJeLPIg9MYBLfxHYhrxuQUX4TuRbLXz0iulqzRVATmG4aNSgw5MhMiCR86xSCSHRrqxmQiTz0GgvH0SvbTJEyCQIjokzTkR9ylb1FFAtG6SPiXpAG7UmUuq3SdFzo0qZ9qCe2dZxYYi3XY5VQcC9kncvM1AJ4iVSIqn8JOpEEbzUyxR/JexlBQ6ozK8qQkdVo6T6B4Uh05I11JrBE23GIXDFHBIyIafK7zFJ40xPBMrk1AZfJATF7Xa705JJ1LvGpoEe/WouYGN9auOLZy0QKNNSjIpH+rFT6gPcQoTT3V00fCxjCIg867LNY/DADC0fkIIMouPPBsIjpIeY6pTDSTaFzUjd6lRjgF13h/1goYlAlJrNF7rw3BUjWDxjhSr/XF2FueJ8rUr0uqlrP/2L0vWldEU6NhSLJl9pZsEswnFlHWFdEYg26uc0VkSazHnlhcjIf+lKHfq8sUuOz0uU85VPJY1okeCkX+GShqBxatWyPYlhZRElEydtdz+LntIjJLHNjdit1kexxIl3F1xWBKEHEMld6dJJpkVIC096Ih2iomIXArCDSI2qDUTBJ2srCWBGJqfeWtM0fsavgZ1vhk3fRvY2LTOGQcwbDrkWE1z3k7loEhICWfYu8+Yh8RPbCR2RrfES2xkdka3xEtsbfdu6gAEAYBmBg26174gP/BrEB5c5BDETI2wwKyR7hxBqwDuq+dlQOmAfdWRG1z9flqgAAAAAAAPibBywlq1F+6U0fAAAAAElFTkSuQmCC", + "description": "Displays historical wind speed values as a simplified chart. Optionally may display the corresponding latest wind speed value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'speed', label: 'Wind Speed', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'speed', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":1,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"m/s\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card_with_background.json new file mode 100644 index 0000000000..52a1570847 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_wind_speed_chart_card_with_background.json @@ -0,0 +1,32 @@ +{ + "fqn": "simple_wind_speed_chart_card_with_background", + "name": "Simple wind speed chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays historical wind speed values as a simplified chart with background. Optionally may display the corresponding latest wind speed value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'speed', label: 'Wind Speed', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'speed', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":1,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"m/s\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json index dff8b3cacc..ebdedcf611 100644 --- a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json @@ -2,7 +2,7 @@ "fqn": "wind_speed_and_direction", "name": "Wind speed and direction", "deprecated": false, - "image": "data:image/png;base64,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", + "image": "data:image/png;base64,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", "description": "Displays the latest values of the wind speed and direction.", "descriptor": { "type": "latest", @@ -11,19 +11,21 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'winddirection', label: 'windDirection', type: 'timeseries' },\n { name: 'windspeed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Direction', type: 'timeseries' },\n { name: 'speed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-wind-speed-direction-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-wind-speed-direction-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 7;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 30) {\\n\\tvalue = 0;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind speed and direction\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"air\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#5B7EE6\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" }, "externalId": null, "tags": [ "wind", "weather", "compass", - "degrees" + "degrees", + "environment", + "speed" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json new file mode 100644 index 0000000000..1e338cd67e --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json @@ -0,0 +1,31 @@ +{ + "fqn": "wind_speed_and_direction_with_background", + "name": "Wind speed and direction with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays the latest values of the wind speed and direction with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Direction', type: 'timeseries' },\n { name: 'speed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-wind-speed-direction-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-wind-speed-direction-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + }, + "externalId": null, + "tags": [ + "wind", + "weather", + "compass", + "degrees", + "environment", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_card.json b/application/src/main/data/json/system/widget_types/wind_speed_card.json new file mode 100644 index 0000000000..45b63875bf --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_card.json @@ -0,0 +1,29 @@ +{ + "fqn": "wind_speed_card", + "name": "Wind speed card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest wind speed telemetry data in a box layout.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:windsock\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Wind speed card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"m/s\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_card_with_background.json b/application/src/main/data/json/system/widget_types/wind_speed_card_with_background.json new file mode 100644 index 0000000000..78e3fe63d6 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_card_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "wind_speed_card_with_background", + "name": "Wind speed card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest wind speed telemetry data in a box layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:windsock\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Wind speed card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"m/s\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_chart_card.json b/application/src/main/data/json/system/widget_types/wind_speed_chart_card.json new file mode 100644 index 0000000000..723b1478f1 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_chart_card.json @@ -0,0 +1,32 @@ +{ + "fqn": "wind_speed_chart_card", + "name": "Wind speed chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a wind speed data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'speed', label: 'Wind Speed', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm/s', decimals: 1 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'speed', 'm/s', 1);\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#4B70DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/wind_speed_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/wind_speed_chart_card_with_background.json new file mode 100644 index 0000000000..dbbb82e43e --- /dev/null +++ b/application/src/main/data/json/system/widget_types/wind_speed_chart_card_with_background.json @@ -0,0 +1,32 @@ +{ + "fqn": "wind_speed_chart_card_with_background", + "name": "Wind speed chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a wind speed data as a combination of the latest and aggregated values with background. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'speed', label: 'Wind Speed', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'm/s', decimals: 1 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'speed', 'm/s', 1);\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < -6) {\\n\\tvalue = -6;\\n} else if (value > 6) {\\n\\tvalue = 6;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "wind", + "speed" + ] +} \ No newline at end of file From f88734c01028ef2c535f85336b771c92c25065ab Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 17:34:37 +0300 Subject: [PATCH 224/267] Removed 'weather_widgets' bundle --- .../server/service/install/DefaultSystemDataLoaderService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java index 19d7780a79..892eb996bf 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/DefaultSystemDataLoaderService.java @@ -532,7 +532,6 @@ public class DefaultSystemDataLoaderService implements SystemDataLoaderService { this.deleteSystemWidgetBundle("html_widgets"); this.deleteSystemWidgetBundle("tables"); this.deleteSystemWidgetBundle("count_widgets"); - this.deleteSystemWidgetBundle("weather_widgets"); this.deleteSystemWidgetBundle("status_indicators"); this.deleteSystemWidgetBundle("outdoor_environment"); installScripts.loadSystemWidgets(); From be7854fb5baee31af0a9455c749755c80134b17e Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 19 Oct 2023 18:58:41 +0300 Subject: [PATCH 225/267] Add 'isolated' to topic and consumer group name for isolated queues --- .../thingsboard/server/common/msg/queue/TopicPartitionInfo.java | 2 +- .../server/queue/provider/KafkaMonolithQueueFactory.java | 2 +- .../server/queue/provider/KafkaTbRuleEngineQueueFactory.java | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java index 7122d5ef2a..d2144e8111 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/queue/TopicPartitionInfo.java @@ -42,7 +42,7 @@ public class TopicPartitionInfo { this.myPartition = myPartition; String tmp = topic; if (tenantId != null && !tenantId.isNullUid()) { - tmp += "." + tenantId.getId().toString(); + tmp += ".isolated." + tenantId.getId().toString(); } if (partition != null) { tmp += "." + partition; 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 22a16de64f..55050ce08c 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 @@ -187,7 +187,7 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(configuration.getTopic()); consumerBuilder.clientId("re-" + queueName + "-consumer-" + serviceInfoProvider.getServiceId() + "-" + consumerCount.incrementAndGet()); - consumerBuilder.groupId("re-" + queueName + (configuration.getTenantId().isSysTenantId() ? "" : ("-" + configuration.getTenantId())) + "-consumer"); + consumerBuilder.groupId("re-" + queueName + (configuration.getTenantId().isSysTenantId() ? "" : ("-isolated-" + configuration.getTenantId())) + "-consumer"); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(ruleEngineAdmin); consumerBuilder.statsService(consumerStatsService); 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 2e3bf784d7..cb063b6a7f 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 @@ -166,7 +166,7 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(configuration.getTopic()); consumerBuilder.clientId("re-" + queueName + "-consumer-" + serviceInfoProvider.getServiceId() + "-" + consumerCount.incrementAndGet()); - consumerBuilder.groupId("re-" + queueName + (configuration.getTenantId().isSysTenantId() ? "" : ("-" + configuration.getTenantId())) + "-consumer"); + consumerBuilder.groupId("re-" + queueName + (configuration.getTenantId().isSysTenantId() ? "" : ("-isolated-" + configuration.getTenantId())) + "-consumer"); consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToRuleEngineMsg.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(ruleEngineAdmin); consumerBuilder.statsService(consumerStatsService); From 54ef5364ec159980106ce05491cabdd6a79565c4 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 19 Oct 2023 19:00:23 +0300 Subject: [PATCH 226/267] UI: Improve 'Wind speed and direction' widget data keys configuration. --- .../wind_speed_and_direction.json | 4 +- ...d_speed_and_direction_with_background.json | 4 +- ...-speed-direction-basic-config.component.ts | 32 +++++++-------- ...eed-direction-widget-settings.component.ts | 7 ++-- .../wind-speed-direction-widget.component.ts | 39 ++++++++++--------- .../wind-speed-direction-widget.models.ts | 3 -- .../shared/models/widget-settings.models.ts | 13 +++++-- 7 files changed, 51 insertions(+), 51 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json index ebdedcf611..d6734f8516 100644 --- a/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction.json @@ -11,13 +11,13 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Direction', type: 'timeseries' },\n { name: 'speed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Wind Direction', type: 'timeseries' },\n { name: 'speed', label: 'Wind Speed', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-wind-speed-direction-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-wind-speed-direction-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#5B7EE6\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Direction\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#7191EF\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5B7EE6\"},{\"from\":3.4,\"to\":8,\"color\":\"#5B7EE6\"},{\"from\":8,\"to\":10.8,\"color\":\"#305AD7\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#234CC7\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#D81838\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" }, "externalId": null, "tags": [ diff --git a/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json b/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json index 1e338cd67e..32a54a29e3 100644 --- a/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json +++ b/application/src/main/data/json/system/widget_types/wind_speed_and_direction_with_background.json @@ -11,13 +11,13 @@ "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Direction', type: 'timeseries' },\n { name: 'speed', label: 'centerValue', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.windSpeedDirectionWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 2,\n singleEntity: true,\n previewWidth: '270px',\n previewHeight: '270px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'direction', label: 'Wind Direction', type: 'timeseries' },\n { name: 'speed', label: 'Wind Speed', type: 'timeseries',\n units: 'm/s', decimals: 1 }];\n }\n };\n};\n\nself.actionSources = function() {\n return {\n 'cardClick': {\n name: 'widget-action.card-click',\n multiple: false\n }\n };\n}\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-wind-speed-direction-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-wind-speed-direction-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"windDirection\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"centerValue\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAQwAAAEMCAMAAAAGUnihAAADAFBMVEXw9Pjb4+r2+vz0+Pvz9/nh6fDe5uzg6O/c5ezp8fbi6vDY4Obk7PHo7vPx9vre5u7K1N3o7/Xt8/fZ4unY4ej3+/3m7PLW3uTm7fPW3+a+ydLR2+LAytTS3OPt8vXP2eHCzdbU3eS5xM7Dztfr8fXH0drFz9jI0tvG0NnJ09y9x9HAzNW3w8y8xtC7xc/M1t/R2uDN1+Dr8/bi6/Guusbr8PPO2OHv8/Xp7vHf6O7R2uKyv8q1wcvZ3uHm6++2wsvx9faxvcnP2N7l6u3r8fesucXU3eLn7fCzwMvCzNWwvMjr7/HN193X3N+9ydLb4+jb4OOqt8Te4uXj6OvL1dzg5ejh5ura4uje5Ofi6e2otsPR2d3V2d2gdlHb4uWbc1ConpyddlGie1efeVTv8/engVyjfFmkeFOgbkekf1ypm5SYbUmbakOroZ7U29+gd1Wfc0/k6vCqg12ccU3Y3+OjcUqcbkfg6Oulm5mrhmKvh2CYZTywi2SVakabb0uYck+baT+ea0SkfVaYcEyecUqclJSupKGjc02MYDuWaEKbdlSYbEaldVDn6OirnZipgViRZUGuoJmsiWWng2KqeVSle1SRZ0Wnd1GUbUqofVmUZT2moKK1kWqknZ2VYjm2j2WjmJaakZCwjWqffF6deVnR1deug1uhdk2MY0GhgGSicEeSXjatfliFWjimhmp7Vy6ndkw1Kyaik4y3lXCRakfOzMu6raWll5Dh5OWvsbawo52emZq0imBAMivGyMylpKmNWzPY1dLIzNDBxMirq6+ziFmUc1eGXz/R0dCrp6nL0NXAwMO2uL3BsqiqflLd3d66vcG4tbaTb1Cibz/CvLq1p57KxsTBt6+EWy9vUCq0qKSvmYVRPzS7nH2yglGPak3LwrugnqO9mXJzWUXc2tiSjI6xra66pJBnUD1fRzXk4t+4sa6xknbJuq69jVm9lGeGZk6XlpyYe2RLOijArJt8YEucj4eojnmXhHiKa1TVzMN6c3CEf36JhoplXF6NdWNP0q05AABdEElEQVR42nSZW0tbQRSF04c05ShYaGiIMcRUvDVGI4iQCwQfWpI8FIRCSf9F/v9L19qXrDnGrjMz6uvH2mvvGRt/D/Qa+vH6I/T0hJ3abDYvWC/zl7lpNV+sFovFcrFcLu/uvt1hU/fQePx9/P376SnW6dnZ2Wh0fn5+cXFF3Vzd3Nzw9L8uoevr2+vb29vPnz9zPzxgPWI9Pz4PnmfPk8FsMBhMZj1Tv9cfDocdfp1Ot9s9OjrC0T7CalNfKJ4fvnyQPrk+fsSmTvDhPGmdUK2PjTccsHH8wOEYuN/oBTDmOOYvK6DAWpDG8o4wXMZiTJEFSZDFOVFAgeLqMohwkwUEFkaDMEyP0PMzaADFZDIZTHp9LGg4/AkYEFE4De42YXwxHH9EQnIYECmQA4G0Wif4oBoMoiCFsAV24sCS6AugSGcsTEsoXEEWxEFfBAwss8VV+AIrDujy5uba5Sh+J4zHYEEcE9KgMYwFnQEg3S5hJA2qTRxpDeCQZAz3g3+u1nQ6DRglDVCIEpGKAsH2OokqKWHc4ftmOGSMe7AIZ4wuzvGZAgW2o0hfXKNAQo7iATXixhjAFV4jfdOQ6nSJwnG0jQQ3neEgDlgkDcpB0Bcto9GaFjC8QJwDTulJztjwg+iMTAwLDCwKJO5kDFUJNEJiXIw8M5KF6xJSiaTKKpnNZpNBbzCbQKBBFKSRRcICaeMwTxAGvw+gUZLgJges1EmB48AZmZsQgZDKE1eBIlhQzoKBsQIF2qIskrFbw41BFjCGy43h9RGu2Gfn27wIYwxmswGNMenBG3tjHOQFMDgKiCz+vAcDW66gWpSx2DYSBLcrfPFKBNzShstIbEgishNAmJ+QaDAwgAICCffF2kAYC6UmdY11GyhKV2ADBlG4erAFFL4gCsBwZRchi9ChNaxCPik4eZBFauswVCNqqtFNUgoNmgI7fGEglotAkYFhvjglDFVJuAJLBYJlONRSH4zFoxUITg/PGW0BX3iNkASMUY9OsXAS/KSyq4rF9KSVxiCKEgY/UxhDUSFbRHbOravOgWIOS5BGgrgjCmzlBVBgwRfrTE+KJLDBwaMTVUIWJKFGwhljZjCIw2CwjURcZHACRkbn/0wBVyQOouB2ISuiSrbb5rZVOEO+0KglT9hhI8YGjWTlvggVeXHPRWe4LQIHi2SUJCjzBVmopUpmDG5yAAhoMkNc9KNGgGKoCiEMZaep/eF/XRXOoClCcESs1m7b3E0DRlkjOV4UhnAeGjBAA/JhizQiLQKIAkPxCVuwTM4dh4Hgvo3oFAwOnqSRFULhZF+dAMfQ1Nk7A9nZJopMTtpCxhAKbCNBEQM3RBTYViVNc8YrllhgGQzVh0pELfUl8gKeIA/FBapknFViNLyrQlklF/CFwbhicoaEwoyB6DQc9ARFGB4YiSIkV3DkTBjCwIMgcgxXkUwzPJvbaRMsqqpqqI9AGjEIg5sgIHeF03AeQEFfkEaZncARKEpjrLORUMkiAuOd6UKDJ7OCKDiGeyfp+7AVJBga8kXCkFQkaQ5vIQSBlenZJIpmsxGuKOUoyjp5AYuyRhgY7oulw1CFCAbvZ6UzspPgIwgXghPpKRZYERfcTE6WCbMTcmMoPo+wnARW6pCEnKFRy2k0wQJHs9msKpyNJOD2kC1wqlAoGWOF7+CiKhiskjI+R46DziAM9RA7c77g4XFBFCGCMGNoCo/LWVxVg4WCk6qhyFkLX9lF0EbwNUEDJbLbVruq2u1QJod9xEtEIDw7sVgiOIyF5gvyiBKhiEIwzk5HuKOdgUSysOwECHMHUUiRnYRh93azRY/jFo5hDJ5UjlrdHDszPSEckg9abg6ykDGg8EUFHDuwMBjiwfnCUQSMIEFTKD2tk9AVdVMEjegjtWvJGiCYGj6IgwVA5KVdJNhUXWQBzbAAo+dFwq7aUScxW5gzFJz4ChyfdGnHMgzeSoQiioQkHAYh+K7dU3EAg0pkE9f2lcOwtNCsRY1ZIl4jmrg0ilNXxc3MiqXmCyjuI4+4qGoQz8Do2OjZBY2ICywl52FeCIXXCJZJFLxOds1d5WUSt/b6RVUCBcLAqAUUPnZmXgBBGRYZF6SBL2CQhqHQI1d5JbkWClOMWsxOFkkPqzeb9D08O1i6nlEKjLZI1G8kpmypmjCaiaPit6vw224foIevF9FGcLjsWYt31EUUCbR3BceLccTFPX0xtimDKPyJK/OTRcLI8PjUPTVgwBhxO2OZcHHyBItMDIVnlEjSqBvCDxmDLVUwpkGiZW2kwgkcx1WjXh/12TMecggCX/ZTq5CFswjpAQMcsCmVSeEM4ACIuLfTF/UxHCAyL8jCRBjZSHRvly1wCEUNSKLQ5azl01amBViABIT4pBrZRoJJ8dTpJJ7cFqt8/M02wvQUCmwoKgRH8cCFtWZmxDuXX9x1VVUbCWcoPAkCeUH1S2ccBQvI66M+aik90xr4TijQiPdOosgqKQI0byPclGZwq4/Y8xU4YDMsuEWiaKoEQTEvvJWMLDFGIuHXVebFpbEQDI3gAyyrD17b+xme+baVRZIvv+/eUkkBPwmiSE4cfNMKEjyrbauqWCOkcXxszihetbANxCvObKgbT4v9PbX+DK7B854wfvFK4igyPe2aZiysnairOg2PCzVVYMiuivzs59MWVasRT4w0hXAoNr1CcgjHzhHc0sJ/AAZJfOXXoCeiQsq80OsedjSRfPrFFygCBLeFZ06e2FEj2JGf+PYzhkmdhBN4kDBXEMigN7ESmXh24gOLoGE9lYqZ8y2LUF5Uyxc+NRIsqvLhkzwI47V4+ZXIIrUiDCxOF54XptoEblWiK0k0khF0vl7rVTyzUze0uI5wuMjZgjWCIrGLaqaneUOvfJo6BUKNJHuIZvCAwR2dJK4k2BBZIDPsic/Ko2yruo3QFVgQYEQrEQwNGNFDMi2ykTiN2jAezzlYmRc0BZaXiPPI7BxmcvbpC73m1BqqgHyqlYh3ERzvOQMiB27kBTMDMEKKTiy2El3YiYMs6IxF+iKz06RZK2whZ6zDGWyr8fBJGAZCLGy08OsIgfDjC0YfchpEcdBJNGqVvsiLCLbC0+KCmyQ0Y5AE9/FXfg4DgYntyhE868TfOudEAeWVnVs3EvNFeT37ZTDoinwItkedrBPlxX7oRJEAB5RjeI/DlipET1tOIgPj8N8B3kUk3dgzO6WqOvbA+Ee4uaxMEcVAeDZupAdceRsEFbzfFg1CK+hO/F3Myvd/FquSyqmc6QYz3e3aj0olJzn/D1iGYPQM4WsStSeiMNRrRVgXL1VHnCURTpKwz9faoyUMzX8ZOo6QASI+hDEGGBexYGSOzGuz491yy5BpyKdIEPyx81xCGGmgLiINRZUSTTvVetYwpzoMj7aSBgShqlrHVbUYAKHRJzwjYAiFaAACtJEgvpYwvEkMEnzdYngUbhg2jOYW0XBumyk0WYRpoMF4GLGcikWXRoBo+9S0TtaSvh9xt/VeiwHCIAp3njJP5AhYvFKSVCXxBCMhIHQoYS0hCzro0IU3qsoTn9rndsvL5TDOTQnSykjGShJIFEgjaZx2sxwLIzjwV4UEGLxG/AgUqqteJApGyiKVkaMMaiNZSBlTLan08ImEObLrPPtwC+/hrkhlFRhsFmUX+XElAQ0EbGNdllCGcoRf1hGd2b1MDe+EV5Qs5g7DhSQn4R0GlAHDuOMJTTC8KhkDcfknUsOGARRKE6KwLubeU83W8elMLDJD8A/+/5saLacIeSx4KIyCMR/aySFYeJBDGu4vXt62W7BPxhU4ZhbsxJ+bheY66j2NAkEGRSO3Rs8ShtrOsot2WOUzZcjsGAEDILLRulfaUBDEigc1FWHPMAu34b5yoCZcJPB4UxQwNMOImPoLBlcEI02cJQyMxEeOaK71TUSUI33Z7g4DMe9Up6gjqkuqegsXVSsjTu7LQ6C4T11ENWkklB65TlXvmZXkY8IwC8SnVIbKque/gwVzBCz6vO/NW8rijWuJpjllF3xCFt/Ug0fjyc6z1iR1H6XCINpSwNsRolBoxicW4RhdGPyc+nokojeeiMwQvk6POrJbFy1F8IIDdQFZeKWofitRyDGy9wQNHs1Igi8jleERhttwRB8BO5wiCI1/wy4sCofcgnbhLAEMcfClnKEKrUeoC13LAQ1vBT4pPu9zRNaJX0y4oq5qFNxWq2PkKWUAiENZEp5Rg74nLqtWxSEMbxAjSayI7ML5qJYsEwzLgnUE0fYBMgxGryIfvROQMBANhs6qQhGuUdJwHUGUe/Y5X5qn96pgYcPou/Y9DZHAx+uRDdZ5Kwq8BMEkgWlkdGV4TcQMkSrwyaOZ9mYMOWcqI1Dw5wYjaASLEZ5wMd71wWfaJ2GYhZrPX9NABy9Y9JnOMQrAIIp0jGy2tjILh06qK0koTRbDUH7k83u4BX855JNhiIa7C5C4zifVWpRkjqRlIE96KXlQkfbpeqpQSVUfrnm4b2HYMY4HOmw9d0szj3JWNJ4Zi3KEv6YMBD/fpQt1GIIBXRiGevBP3qjmNEfDLUXWEZHwUpG9p6cY6Ro17+S3Ok+P+mKGoR5DMMRi33i6Dd8SBWlsu/PImr0WiICDMsQwEFqYhXvWxd+0CzuG9wLSBT9XzH6DB0m4DSeHu9AF7dPu6UEGv7JPCeOC8UXKwjFd6BuTvuOVqoe/aZ11QylUIRDRXhADBLJUgMWAwXOZT+xhGDqnJouxLsJrGPHSLkTCC3edSGyer/lzKRGJNskIWYCEbiq1fkuy+K8uhEKxEYdzpAdlwWddI0kojpEljx+eT39iCt5XyyIRotBK1SQ8C1c5kSzkGDXdsnVmIXEn3kdcbsQBgunBSV/dYeuNuDarOqzOp/a+LqqS6mZrOqUy8mCGjwxDLKQMqIJ58mdszXL4K+usHDGJYmHPqLB73kWaIEiko1Ab/jdQaK+qs9lFluGLGAkjGk+PdA62qvNOgCwAwUkyKSN+2W8pksX5MaQBGMqS1oHzDV3EYOvnVFbBwu2nRlv2zmgwspT4puO47Gld/P2iuqqZJzsLXJUXilKGLcP91i2KOrO3GV8faM045J2UxsIskV08Pj88g8f5pOMIzyMe/n6nNqZj+5wiY62Kec51N8Wgfd71PjzWJTXTeddH4jqowjwZmSNC4b8lUYjG/tiuoxm+ACFluKKKhvcCgMBPP5Wc40dlgAFI/K7OExT4GMW0aX+ZGaLIo7s2Ax/onxAFpbFrt6wMtxh0jEgTceArHEECPNhiFAkfSg4MQ4UEz7aBhtcBs32umSROEQVhQBlME2piDLbgGJpr+fIan3lllHYBXRCGpQHrTMtgiAWe3Q3xMAxd9ExdfKsBsDvPtE/D8IW+FmOaE+655fR380rAJKKI0DvLOXuP8TjSpF1PSrdwp5WzcBmGSKgR59hT9nkdJLQxUt85rrMlitvxFi/JEweT5EIezwLHC99i24/6PN2apSHrRJDDbVlFz6kkWRGGESzKNWAbjwEj74KLBoEAAg0DEQwSR/UXjNoX4TuEoVMJc0Q4unmqE7+9r1StOC97PvO2HdGu9BHGLkV2MLwsGvbZE2WlLLBhJok1MPCjH1AwSdBntMkvI/zio1B4EP4xS6r9U/0W7JOWYWnQPCtFQhhmMe8Tc7EaF6HJQq5hGL7o6Rnw8WLAdWSrv6/aTzDAYqkTSZlnMKkcYZzIQgEMugxuGGJBCtPdxqfCMfcYd22gUzDeZo68cpJ0GnHhNW9h0ECTRBdGhlLkBsYIoKgNiYuqQTDsGQQRH/sFskQwJAtfjY+Qe+5uKjG0J2ksdCb5oG7Le+Y3qQqaZ78pj4FOGQY5MKqoPtIMQ7G/imEWUylhtK1ZryK5PFtZUq2LZp6MgKE6EigyxEJBXZBEaCMuHuhyY3mnD2nqPQNGblblniDBEbD/mgQgNMjIuwdicWkNRnmn+vDD2wcehfc14j2z6IVkoSyYG2JRIPgxjAwpowqJWfAtGLFV1ZlEJJwlAAEahWI+qjpHxGJcY7tcfBn6H19n06rrGMXxx4S2nLK3EsrjpZvI27ZFUSZ6IgMPKW85gz1WBkrxCQyVsZSJj2DgKAMMHEwMTHwAn8P6r5frt65zYd3PfW9Tv9b7Wtd1Xm4HKNbuFnrB7gGnJpwFVjLTyBYf4lqBBIu7doWisq1wnniMErGoDvDUA8Z5Go5Xs38hxWhRlaN49nBmIEbMFCQKqpwloSJZG8ACoY9A6IONsIBRJDyoioWAjEgCh7ISC62OQm+OUx8vFHrbgZqeiJNfNBgarRJISDHoe8a5mjhN0nt9sEgrcRB6JP8+JsF3Lo2tIAEMicdUKtUCUSjKgZrLkFZU+6KScJ3XTRQ4T7GI5POJ49E7XJy7kpk8lkaSIt3wMFKrKdOJbjYx6OgUCsEg81xshAkJKDQYaOudMwvnoO+CYoYhENINsQidwF80QStGIo73rAKtRu5pJzKRad+TJWCTmhvJfXIokTFJSJ1sp+PJ6aKbK9vyoIq0iWri6B6DZo75ziKBA8V5upEMGjVpv2FQcjTfyRqbUGTpPsoRjqGRhPcDFFhIZFsUJMQRl1QLyZJ24j3H5preqR4RiVs9ioSREEy7YshdpGZ4Bi5/Uf3Otf9bJYkbSNSpmMiYrVrFSq6lsp2ZEbmW1CJpnEdPfHIY1OzEEWqSrhn0MBwH6yhpJLjP2xRXu4lMJArE6ambiWAYCfoX4UAxkGEjTzqM2UTueYzlrTFgphnebCRYEEcikLRxu4R6ZD4/sW6kDA40dNZsS6N2b/8SRbwU0Zswmux0UJeGZxkJq9CcqdEbRxIF48jQKEQwWD3QE6vAk43UrQd59qyq9geYkUjiYhBMZPGe7jurh7HEkvKcUa5Wk+9WHKc9qs2wEWBYPC0YOE/iCKWZFOOeqkiOLHtaIMkZWjqLRxJEqgYb0SLhYdVQVCpeNgIKunxMz4SD6gwWBaORaDaSdQkBVSwEotymfsiuFjxFg1gymlv+VhyhIJFyBIrc3jLJRTY9YSPGIxMM5gLVxKiDNdMK2xRUp3OJ/3G0aE08AaE39IKyDH9RHArGqTmN052BMP/Jag7NHPSCDsY9ooG/EAmOai7HrljEeJqeZ0VVI5Ew0nOCY50xLw1g8RidvjWoUq0SUoXC37QQfcp5ioVg+JgklAIzQS2qnxOus2daIffD4mGWlcRBNEoxOLcriYFiVavV8mR6BozhMWj+0gDO2Rn9HHiYv8hx0WIjySFIEEnsJxgmUgpHsczO0IwwkiPpxT2xemA/le41U6X5e7tYUJq5q4jHYJT7FAta4dAQiBoZIQ5CQj+nr7vOy7/lN6GBwyCmlpWEmTBPZdROMSIph8EWhn65k6IOsNGI092hFeRaBSPXc4SD4Wol4VpVSkEziCXLlSAEkrWFMfcwVLVbEMnpMv7CP3CI91nBcJchrSiXwR1C84xELJYTA/KcNW6P2qyyCzrhsZAiGL08KxOpa1KiEV6rB+qFU5PMikHV3mEs86KaLlOnZoax5Fv+XBEMOc+IIvmpyqyEeuSGFPxVZ8EAbVgJOfijpRgxIUkUdplQK9xnE5kOdc9GQqG6lKp9WHQLITUshRzcHgTdKNnlKe7MwpmQ5IY8/QtW5O2lr6XfCCVMl/WIhefgycCJmMhfiAXHJ7huq1BIlpKEBEMY4rXNHLxFeU+9wpAs4jFpOqFfes4ZRlsK18IWaiEQ/fDEPFW1l5anRAlXtnLa4lZtNp6LR/oLTVUpVl3oYbSx6mQluIs8iUiSgXWwqoT7vKv3OvXTEzRgsSUM8s559bdo1MGzSsHHWZIwkgBhT7RzXC/63tZLz51rInAuDrUlH5rBWEAsbkQh+b+NFMxkAVGZJ7UqnlMQhGK2kSuCsdwHknfm5KCdhT7PwdnCyH7OmJ4RWNuep/d//S66cylGJlscn5i8Jzaid00xpjiin1wnm0pTpaoEo6KqXgKqHkg0I9m2bScTwXGW9ySIWDO8PMbRC5KSV2tDp02MHo4Uo1hE4pnl+gvCEUfxMr1gtTFP+uMu1gFzK0m4d+1f9UI4IgsfzoLxiD2gQK7ITLadB9QH41I+bESKwfFlpVpCEddhZOYZLJRtFQujEcVZsfDcU4qh4CEk516Q0NrKMUmNl7l8bNyoBI6BYqpJ2HilWGWXTwKKrEdgUThOTk7tEYwUAknEEH0zuxAMe45HQyF5LFPwEozEabQ9zwwloiEU2s4RFxNY9Bv6loIEErgMie9gsP4LDlttnCuSVS1O00BQihPHsZ3uqFLRDE6putRwednbYvMgYBBX2xTxvsBwnxTCrytkjpirjfYTidVKhnDAiIFRiWDAoqozPRgI+UW3kPgKhePYNsGgYB9tLT8qUPcISSfa3Mx+HEv0D0drmCNW0S4WsX0hL+pJhsyERSUWUjjHnC0M+nzT8KxQ6DvX7MQQvTFAbO2LXoo0Epv9TE5PdiTgohEzgT4esafafCwquYyVFG+FZ1nCdHnAMAZSCgOQB7rvFQsbn8lE5kOJ/x5VMRLBmNJwTnEHiptfn6ZmAUNJeEXU7ioKhzhIMdxnjHOI+E+MxHioHe56kTgShY4ZkXuSfbJ2YFGVY5lGIP+4lJGwAIzHSFnXf2ltEUfEY8C46fs/bp4Xf+9C0AlI6LPJSNxMmJutmWcpBkn4Y5RohiK32JJGFiXAKCsxzchVFH17tpU4gJFXYuTuAWbCmmeNmNe1LW9ffPP1lx8bBGCQfycM4YCFXimG8eiaEYrBumvs8pFsiQWaMYWSus5ybENzeiKvQYZCvw0jZE63iCWQiImRSZ0wCscpgUQ2MK5+/umvTJR7hVqSniL+SMQBMxlWIm8xULiFmHhY9RZGZxEulMsPJI+OuIpeiEYzj7aec3eQWMPqGkvmPHzd/hWJqEZE4+vfsnfBwGy4TfwmH5PNcGyHXStTRyjJi3N8ZSvEPcYxUOSNluU9E4biSOwAYyRerespn3FOEs6YpPdz7vjPWrW7T3LPzC2SR6y5vvbh17/fgkbY29tZc7JFWN3sdRik4FW1V3VWMGQjR/q/IqHrUuQxYmzEedV+cvelbF0UDT1M27tmEEw4NLDUJHR0XJghSi3sk47zxWufXn/HkyxiCL7TGOQnMIiJy2HbMWf3JDxrM5mJDKTESOirtifnBlqBFijmFbZaRvFcS0TItjKqUqyOc90cb6coaXcqreOiW9lGqRb4bW989sGXV4NA8xRrUG1yaiwGjNo5YNB+9FgyWGS6JRDhM6hWucURFukxiKri0MbtGVRpAE/5lp4+GeiDknWIWBts0caRo3jjs0+/+uEuHwHQ1ptBXAn7QNxMuFgqpBa2IgkXCn1yksiR1ZomKpaE93yoj1VTMYKFRmfseY5eeBusFgoUo4RV6KXVR66FjWSW9eZfn3/6253OIB0FGOJXAoqDOdCQzDqrUr1Hg0TREAd95S8k0dTJNgYew9XCfrAQjFAMhN3GftSfTHxclQINWp7xZYA27TU+w+qFJ5tG44NPv/tEqpH+gT+hEXoPA8XBZTfXZqOVo6xTfjOtRDDItnpUpUCbRswxNyOQmIQHdQ4CYk/rehqN9RxejdubicSP0wJ5VUyiMKmtzndNN66/eyUMooT4IYEEMGr3Qpt8mVwYDCRAmKE0EqEZnMXDe0rqrL98JwlGdXRItqoqQTPwFj2SYCJOQoLz5KSu3tSMpPHl+52Df2Y5HTw2wbjhssagIcUIV+EJV51wH7mnf/MS3Eq3YEEs4eyEULiMMDIdS5T864bOzVz8S4YhGJl1FovZSOQ0RePyqx9OTBYvUQj0HMxYRCJhkFlkyS4MqMXRKBy7kQiG/AUXb033QMQiRqLATLgb2uwjPQaasaKgIFmulmr38t3GGW70IjNN6cblT04hVaODmBxGwohMS0IvJyUdBiUJbYxSjLVA0xPpp+QcIxnFKoMBWDBW7XLjwCiPkTyvUzRMzW5lKT5T8GplvWG6cfnTlaQADXxnaMYhzORsV3fm9PuUkoO+cAgY6S/SY6AZOSlhFaPM5N51y1Mk2vJByhJT7SXTklR95o3OW2QhoqFRUY0P6e5FMH3xry8uL/94zzKq4AAEd5r5F82gDx5tHKORvRw5iyPZBShM2Ijm3xuo0QBF2gin+hWOcJ3EVVgAg5lRP7jLlb++wycWBiI4RBgJqTKkaPz8FhCShBgglmPsD2cykyeqrUWHTx95TbGg0cdOCi3gh8eCI6cnhpU4iRouLwmGs+B2pf+aGFXR7nrRt8HrBiGxQC3uzLZFOYnX/vzi8qvrL55shqF+AhH/VTAMx5nR2GV+ESyiw3fMJSVGicCgJgkWAWNe9XyqlhvbxhaZJxaCvwiZUMxjEq40dW/BZDnOFUnodEYHPHPNq39+eHn55Y/byYARgm6c6bPfn+33u+Y7SyvCXeSsvV3F1mDc37xnTAdgUQeuxjLfAy+ngTBupxtuPChVlzlJz7bKXeQ8gOEIKCjXKcWu/nnNaPx0erHp/x8cm7zmfjuYiVyc7Y3Gftvlriur8RFB7PUidUQRnGdeliIcLMoXDEu4pBgxbm8tPn1wnviLpWxfDuIxMKoRu0mxEIhJMexhQOTF6Ok317748MMPf39lO1yUPlwcNtmNzOPicHFxsb/YS3ZlIsaiD87Y8YwzRsir/TpL0eg3kNWSTqXi/cwuV0MHiTndWvfkU5wE+YXDKBTUZgzYJZQgalP88uc1o/H3excXm35uFWeHzfRhM9UwElvAOAsYWaEGhmOy4LqtujVGuWfYSCSfzJm5MJvblQSD5MLexURmxVi9J4rhEhu/shFOjzBUFg0kC7MIIkHj57edxt40ZO//5QT0DZHPkHmw0Fh6URJbGHoEo0YDnMVjhFZh1ViQi1OOiMaIp3rnMLLCqEScu+jcSJRb6KWX0/JOfeh+VzTdtm+DxrsOQx/ZRlLY4s+ZNKPfdFtAioN3c17NisT/VaOsz3T8bMBQwrXE1fNgwZqncJRmLJPEhQS3QuMvAgZbvwkDFvR8XVqrQpZyzWi8aAAu9meQEIR8z87MZ0gSAyxo8IVmpGKgFlzg2OZGzxUKzVbPoSEY9LVKuLtxReFTAZNWj4RepBBGOG/HZKS6F5lgmSYEjc+uXy0IYlIKoddlJ3fBihIj1ezj5OYB+YX0gqjar93qgyOqtMgwDAIsJhtZuuFEkUkv5DolAWNZdG2be0My5ZSTvAhLuX79m2ETgwOyGyiOud7JfERvjNuhQbplwiUQ/R+OpN3HZnhZCDMSvYmCtpaeKQtvvd9Mw91j9EuUKo6EAOJUYVWJhbtK0ZBq/PxNmoRUw2XfYZiESrDWWDKcJ66ToMppkj5EG6vh530wMMbLlGZpJWvLkzQcxaDFR1RFLVogAYR9adzof91ofPaZ0bjqLFIlwLHb7WQmHlahAAcsZBoM2JvJVtHgInVQSLiSzptahJE7mCOuV8kTU8tlQMJqko9wF5FhkF2QbAWLg1vJP4SdS2icVRTHP434iBgkiorE+Bq0vh+jaMSqTDUlGE2x4wtdZJFVIK6DKzfOzkjWMVgFQTcuhKadKA7RLBKb0KhpAw1IAtWCDzAiSbD1cR7/+/3vne9TT2ZGXfrjvM+5915iiiFh4+Sp0UNT882DwiFViGwkk293JRMUXqUChu9Bmzr0AIetN3IykBfuaVQ1Fkw9GVbBIqhFnHemNiLS9gieP2XlQu/JrpYLQOhvkm0FvdCkSo2icnK2MbU4v3B/dySZfjL5ff7LViYosMTnn2hq5hexcV7Ep7/4Jkd8jlmE6RbzrWAm9JwQ9n8JRFBQK1CRKAkTnGcHi8I5szS9QDNLMm5lYdpQ+fqvs38uLr6awFDpvuyr5ub0cGZlak+6oiS/4YKUgchh3CKpp3hOn6wKCsYRHh0QEGRxY2HRk4uNJZrRfp5btYItDB+PYJ6aVCMuHI5AI6AbaiGuGd37z/7113uHjy09GLSheyTTf7x0bHN6enhiUs0EJMK2q1mHstAcHA+Lem2mHyw4YjoAK0GpSpehNPoVRb4Nbe+/AQaf4ijmnenaFrJOn6fisjFFQRhkkcxEKpZiiL9QqcBBfHDu7O72xunjb2Um5jShFJOTs5OTmZFwDkzAByiedIok16jjin0aCWJJcBkMJIgkRiMeChBG2UWFAoNBlekF2xcpDDpPjocQVeVjmYXI82/ujo4eafy0Ovd0Bundu7K5OTUmJGZnZxtZckMhcLjrVGE1gnNGfpE6ynaQgJHgBIXu9TkMjIoCC0xUg9Ogu+BMNVlV4n58J3DguC5w0H1yIT72nAZDE64QRRcmRUYnh//cWnn6AtWKfV/MC4kx0Qlh8dPh/ZnnWiI40U7niQtjqBg8msiblUDDsi1YieK4DlZiJUnyolN5QcLZWbp2EN1Cp184z6AWREETwY8Q0Y0LrU/v1ziqPI5PTp7dnpgc/v7c94uvdvQ+s7LYGBOFMBarz6jRuJWkRsJ+pzsMkziOsCJJIomy8BFr2wvdV8NGkIGXn9tl3ulC32kcOGqnjaDFx5EyaGAEIEYiOHpDVvXY5MS57fX10eHxT7//dO7Um7OzJ86cOXPixMzG3MOZybNJwW5L4T0DWpihTBWNEB5wnZirsoehzhMolATawPL1JnB0Di+6txFS9hIeh8uh41lFEo4RCTYwaCMsRjgrlBaWF6tWsYf0aqR7Zn3n/dff/Xl9Ymxs/NDfu2dElv84ve+hDCJ5Rpp2CgoNIWnvN9cMDpn5aCJPdauFwGNIgVZ4QDM5LgAhDruqMFx5a8JkK+/+soPBgiTPwHNRpbikcr/8qZXAfUqaeXD7m7c/++zdd95Znxg9svvx+i9z+zW4Unp4r5R8BQUPWg0w6cRRZs5VWZOEU93XI6iyqRPnGPGDC2RBtcD0DA989bGdo5rBUELnycyTakEaUAuVbvMZSK7mzrz73bffvvHhr+s7O78fzdrFSMBEFEKSdMaLB9HESFHQZZheyPZWTb6PIOGKYSQ7rwyp5WMBrv+akXAvp4ojqmm+BedJFBgkGwnVDSvVo1yzd+7j715/f2fn4492P8gKAhZQDBU0tYL40mt0u37hxUTeiIGVTxzD4+2mhaswSlt8zoL9X52ohqDq/gKxxEG0w0AQucRgIN1K6jGXuZ9/Xj9yZGf9uawo0Xl2+etRtUBQBQkVIYFSlXoBEtCMkIZzjY3tLb4m+u8PZ0KSM/5KwwXXroXZGWcCDCIKJEzWK5ZqKQrUZOYZQOP0+vqR0Yn1GSJIzQRiJiLtb0RVJRHcBWckIEEWnA3IVp/D4EafxtRkT75wKzScxcWhy5cnGEk/hxaCQXvazGG6FUxEKxKLJNQN4DgwOjp6aPjE4TIYiKcaTntwXTiTC6MQvWVkYiAQVdHE4JKjF6tgUbznlf7iYtapQkNh0GFojw/pFqwEkQRxBFPEdt8JbyEw1Fl4gkHJIEcFxvjwzPFSzbgDKPTHPWcPbUQomCTLSixJFAef0aReCIe8bodesJ0DCo6DnrM97+zUL8btygRnBWgibF/EztM8p03JqBUJjYMTE6PjYxv7S2G4XvRgTqTyVI8V7LgyRn/S9i/Pk4SnruzUFfe3ePKMDoP9i8AiSLr8SxOpGgmWZ/oX9S+usagKf4FdA/cXlnaa7ySPLIexb2JClr0Wsv+AMQDHqb7igUcRT1GMyAdPJoIEWESRhLWqCk8YwUxwS3Z6sylA4MpGP77M/TXYiAGpJj3PpIGR7mgpB1UNnY04DkhGeXhsYnh8am8pDEPh2VZIOu9qtlUj1s1JOp7QCpUa5qoQlGcozjA/K1ZnVAqwEEnuO3AOKmhukYXzyN0mDMVMRAQ08kZnpt+IxoNjwzKVf67rv2D4Ha8WRAbmb+C10LwEQiQKqYMKQhWjlpwdcCNBROXNIHjcKoUB1ykgePCMdXs1TzLShk4aRvIFxop+kXT2xjnGQ8aiO4YhmvFMKQw/MYGdX/iK1g1IOcN8BJ1wtHN47W0NRsKRO5/hKGxCY8mTKPhIjaNA+1e+VIuqdTD0yzgCC2GOAXehBFwr5JOYSGwmvQ2BMf1B1lWCo8drVBFBgTWU1rUWU2PXybkAYKDJ5yy4CIxiFZpBFEw+uXLAMtXmRaEXbh+A0EDCiqSYX3AkoOUIki31F7H3TGE8N2arPF05jS776dJ/sZHqAPq/6Go1H7d63eOqgPCinddY1kPRXqvVOCW5120kthLWI2lJEjsMSNjaQpIRaMQwEEmSzJPbnFKoQi964zQcNkJZaAiNqc+7ukDA/iDW4AtX/yLtXGrCSMxlFCtVbvRBBEQ8c4diEAVjKsuRsrMC6V2NMBYMjSyicsdTvvAXaOZU1E68lyPiMFCuJtFkoyGaMX2sSyUjCdMUb4V7Y2sAh5fvnNczeDARZuHxm+VkwR1xrqUoigKNwjkr+k7MSGAidg8dPYYK1SK2kWSdsRKiiMZVB5GhqZNFMrJmMFYCDIEgAqNRh+H+k53Oa1s2INEPivZkPQdzAT10JV89ncgnutMLgKMMPIVxYd7vTJOtgl6kG2zpXk46OatYZO1mcZaTSGA8tmwwmg4Avxn+VdUiKVO1D751sxgINANxRA2F3rOmoURQiFbo3Qe+Fc0XNNNAUvqkKtudYOFa0elqQRtRGqE4490w6TIKWnwVb1/kDqOX3pNyYPlUQ6LJPBTDJcM/vJ0DEqHVuTUgIZXdX5aqGKvWhEat5s4CVyKjJmHCpWIkyiZFqEecB1/ZBYnOHAXnJGlBAhTUDAFhDlRYAIaRCD+EMbd8Shzo9PxIVyruM5QEmxc+Gtm8STnwuQX5EkV+0KiGwj3ZxEgWoZFdlN8hTxAcF4XMkzspVbYw6DxTM3HtcBaWbxXrM8pJhTE+3nqQFHIlySwPv5kew0Jqa8VKEV71yriK12ZrbiTmLuAvEhipleRSXpnhGX+VTuuHw3caDPeeGkxsLkAYHDAjsnYz9YQU7aR7VWAMj49P7esqSoZaFShQjswvWTUiLIACV6hjiW3wvkGBIR9hocUqci3e9BryrSSKpNemQ/pCPYKNcGZbdrGUCnvhPHqXD0ccB/o5phmpB81GUp/Ru2ZmMj71EhnkUdZgYGZmmyjmKZpNn6ZGw6I6j0+Iy1AOyLba7vT0kBq9q1rsd/JaPpYjSUTFkMRh8OQEjSQeClSMBUT3k9KEq03eWl6eUZ8hxUlRMvgLTgR0ktqcl5/2J3cHB4O/GBS1uJeXyeNBvHAE79IkkoBCggI0mHLi3jWhYCjQAjbhUkp7ly8KJ6RhJCgFGKeX12ZMMz4ohXFzHkhYiyy1/GFVohAWgkEtxExEcgsVuAs0PbH1ivsOyv0Fly/CLop9MB6BXsB5VnGORIQ3SbUPz3xeBMFklRwKMBYMxvj49BelMMDCBauuK5v0nGYhwkLEVpVqNdEKc508mRi90BJbSdkCBm7Z6iscODMeUfu3s4q7URK9gAAF8wzXCsyYWZQUYGwsry2Padn6+X+aiZFAZbby6R6O2R2G6Ubteu/mCA2oBRf6gCK1EfT4OFr2fS0JH76K0hdfBF2NI6r+sBXOYpVXSbFA04TLYCgN9nPKZE1hjAmMY2UwUoeBtPPxLTvLDRx1tZNBCOIpWCSPniUXHrRtu8Yzs2g60hmOp6JEzWeqVR8YxXdgMN+iauhXEwynkTTDS+XpmeVfHMbS/8Bg+v3l1h7YSBA1kkHLwOEsIE6CCzro8VEvIE7CaXCPT3F08oFI6AUl3fMEjfQQojkNzlQDiSIOS6uOCoy1WYXRbCfRARjRGxx7bJZ699YtZFGHz6hpRL1XYZi/oGLwYpCQYIgUT5CgZMcVyN7T8oVf1QpevGY/LjxrBRJggbBqZbt2dRhJSrsYLNJPKwwNrdPzWblm8LkzzTu1eXHt1s3CAigExj11N5F7tUhVhxG7i+TOcLMSfyIxvgQjvR47v9r15bCDchFYUDMAIx8wY7AKA6Fe2MhIQYgkLCApjMMCY3VMW8KLvaoL0IkOwOB+kvU7fV/r2q0eQ0F3cZ/DcBpxyQ4UKEgAg1VJElQvtmeceEK1rzMXsEAODklthMoRQACGScQCUWSkwCLLVmfWNg43VDVaDwsC/ZCIwchNxFmITvRs9cBA6voVDPqpiRgL+Ay8PcyChDEVF5umnXDvdNrHYZBFSuIq/HoPA1bCGo0ntisi7jEiFOXu0yuxZYFxQGBMT7cOggD+9L8yuE4+tqDZlsJQEPfUNe80pTDxVg66fKYXDiOwIIw03aKJEIboRUojvpowcZ5ggRsJ8RNWUp6Eu0giSYEGOhYaTA4fNRhTB6gWdKBej7jD8GCimnGtOQt3FQGGRVWlwRMD6Gwx2SrenU7NsNsarTbTSNJHFDENS7MEhqkFPUa4Xws00Omz0h0NrjZ30V2AgWBy/OCYFSevQiPwpzaTeT+HEwEzk9tNMy53GPVaoBGScJ4XKK5hMMUgC/mg4Rn5CypGW3JhgnwreksACQZ3UrDcCCGPcudpNOYExr7HGjYs+MpchqsHDCXDQDWEEmvxSWgdqAsNtZC6gjAWGkXavWe/s4gfBvRQUsi38r1fvF0k7wICg3mKamQl6jjR8ixJxFGS3F/BjLm7PdeSbxkOlZMzyxvZw42GwvhctKEjfJ1G7DPQBpfPnVuDphd1mAjUwiXNPHEpCNbkuf1boKEphrIQDKIX8psbBxe2PAP332swG+BtppeEaSL2tlCRSDXiefgIaJQFVZMLJJgsdPU2GjptPSYKETDAVFQz6DD24ALgxzf76TIMBjWDnS1m4VfTYRSu5tNvKNyRevap0FOIfYiBxJ0cCJue8hsGzFiUZ0niTQy0f8sl9PZmZtaOdz3UaFg+7iRip5HDMBo9SDxXNvcOtsOgjfTbTDUEVf3w/TcmGKlicNvVUNB7Yh28ygScnpPLjTjmT6n4bJUwRpIoUq4a+wTG/q7sFIYFHSawFf3JBAVt5IHmnts0jKy09g4OJjCkJkGLT9Wiv5/VWTIwKg2rpCFCtXBhtul1GWNIIJGiYAdY9QISh5KCcCZw/MTyRlfHBQ5jPqNiwFgyW1zDjtItZ7deea12a62+NH9A/MU9kWLQW9BhXCcoooER++HRdXRIxaOXnFwiGFWAiM2D4yJmWgwjsVZAMYIUSOgXosn4gvzjJ/Og8w/FmuE+A1phMJrvDTenmgtvvfDl10fvSzIM1qp4MRLlmR1YRUUi8uKlL3KqmqzneEunTDOqsA7emFOSfsNdGAljkWfhGJxRLcrcBUT851H5//5aYUy3ngYLSoa1X4upze1DU2fPnfvzhx9/fGKvcwAKGAkSrf64h2GFu8uLKkUribbCoRYKo4964RfFAIXFU+pFYiBOwsNIHkrKtYLLBhRxGQ+KDqyaB23tL8JQFmEJeml395ND063N1tTu4udf1ep5HEFcDXrR328kIJcGFFcqiiGNqkOJw+DdD4AhmbgrRxWra+jvcTeeU0RessWF12KiNVKuFPqlPHZi5qSaxKonGgdJIZiJB1VkGCs/TX7y2+7u9m+/jR56c2rpi4DCpF/iiHsMwCAKKsaQ4HjxvKErhtgP5yMcdBjBTnCvFLPv2D54Iwg4VNQ8XCP8pzwBZ9JJFvCfcx0iJx3Gcx0d5xMFNANnEV3q9dHt7U8+2vny68nRI+9tNgeUBERgKAmRq/uvlo+iIAwlMWS6MXTe0NAV4jqHOBrwgRGd50X5/YRVp6HXYWM0whUlEdpHxbIsaIbA4JydIEo9Bf3nP4ydS2srZRzGxyaKeEOFqqDUzRF1V5HSumiVBlqkDYamqQ0tBxdndcDAgcDpFxh3FbouhWaRLyC0tg00NOmiTSpNoRfoysKhgt2JC5f+bzPPvJkZ4zPvjMfjyh/P//a+k+Tqt3UuHAYjDxImT12hnSeX1c/Xav7GH935xe5PhGPbb3YXlYT9MOCMwGBpLXFsYSIerxIJWtjSMRSR/BmeIOKFA4ERkYKwl9fYGCbBARiJBTWmzOXVjfx/70gC3ay7YcIwNF3Y0RkZ4zO/tvb37ueUPju9+x+f/vqr39hvTTMMAQEWigPGIBS0TC8xCQkSk8FQFJGxhBeZAl2Wg0K+BVsGMvaEQTAUA6ayOAvKn9cZVl0S6GZ9iOR4w7NjM+7DZTvnI792+Vt7UbdyOu0H4dHsTnNZnQlCBELuJBqAoSi+IxbB8cBXryBITDad6QuNYgx8zS8tvnUEEVuE7SYixGWRHiUZvjO5q90XGdaqhkkLMAQIwxBpvmC1/drRzSJq6nSre//zr782zhZHjQVA0DIYbAxIQCgLk5JIbjHewM/R4CQVByMcHrTMGCCRWkyTfZHJvLjanciwzm1sDUkgZ3CICIq3hUbPr7041Jr6RVBIpg8ffvT9447SMBxKAjC+Bwu+8GPUoniMoN9yX+LrL6Uis4V7qsy2eDLYF9ZwZ66vLjOivZ/khb+uGQPy1Bhwxlmtdo52S1MnPVYOLzb9/U7UGEAhClHQQrKIwzAQdGM069/jVHOEJGhhCAlwJBVTkIgbI3uzu5MRFTWB9oYyRgMw7NOIBmN+v+b/ic4zEI+qldZ+cx4lNQARYyEniVFPJMWITakEAi04PjIRJAuT02TZIAIG6b0FNrG4ol7t7mVEsxomZxmxBi3AEFN8KigMxt5KiMJmEuq4RlFIBIax4MtlkWAK4AANfOAMLCxlPLLwgMQTzkYnaAwuqWqNvauHbzKkoaERhbGfAQvAUFeYmrXGOgaSYDxTFEif/W0nEoYNZkm2AAt7cw0bWixUVLCwjvMRUwALwIidjCST4Ovo6jqjkg0NGluzQyQBwogUxtugMb/4baO2FcAIxzN6uh0GUMAVgBFPFpjPkC+EBV3Wa4HFmLAADcqd8WoaZ5GcK2hZZb3cPc+oM7L3CsOLsFBK1GpxjNASGBd+bXN9lEiABofIIBiIEdjCjQ/39EynEeelHLwCDV/YUDaCj6fKhpbQGNRmQbp7c7s7JizofpDdndOxIRX/nfzDE1PIzTA+2fRrp+uCIkgXLLCYcVjEOq3v+HgEMIDjNfFFOSipX0Y+t/we2nBLnbyMx4iwcD6F+L9yBRyhLDLFAymsEhAXXE1+aM4GMGgJEQ8pY55Wb82v3a+TJcQbHwfOAAn04Jw9tfE06YwKpdiCpzN7vxO2IE/IIhRjTIJ4sCvki/cSjlFdDCkx4lbWoyueWNUClxImzeIQJP/BU0sIDKKx+YPvP6wri1EzBa0IjNeJRdiEGwzlIa/mJDWdZTKFKdzvxFs5FiHCg1GQ1BdCg3CosJ2VCCNF6g7W5W0uhNGVMGkuDPXJQyGhXc/22oXvX6wrB9CYScsYKqRORIiTN18u25eN4TRVYcgvT88SB5WweETWUAmHQe8apHNAKWHd3igLokEbGvrRLPhCn4DB1ji97/n+5ZI4QwQaTuepgTIjYRL4gsLErSJ6KIBf9hIUzxiF6Y3oywZjzMJwGAnyhpgCJKCBMZLNhiGSJQa5gx0OBdUOT60/bNZjzoigmD/cbp35tW6JAKCUoMPAcKa+qM7DGPpD/sDBGOhiFOWyfPXas9eeWYCIyBCzkjhNVkZQU8N0gSPU+HFyujOyehpCIERHV+taNVgnDGNtsxODEdQRvo73F/d9/7o0iu5zJlTCbNZ5DBqvvCQsDAXdfKJafrmM3wAkFs/oYh6zs7TeJBqQWAKmCFNFeFbGV/ouTjYaHVlTuIdFOfOBI8R0dCAf2jtMdoYeq7Yarflj399ZQL4AjqTxrCUwyBYspuEmT2JBtghYvPGMQKgIBUC8wzEy9qaWkTGlQRFiLFwYCYIVQiREIcsPUjbos26vmYXp/EBeBW3HYCgIiZLji+nppu+fLKxEYERQVImEwVBLdFY4Y7wkMPq6Tn2bj2kwiByzeCNkIfoApnhzjPUoIGEgbCYzeSkpAyQEA8cFWcMohMYobuxFYCwccJhs9VJzxvx0664zPX/n+0eFaYeFyB3P2BfEo3poCeM7xxUSIhIlki6ExhsQh0jgjAnFwSgeGQ9UU3x3aZorosYgELIECF0OjpPbrBQN1frBBjvjItEZZA02Rm9+erFR819UnQ1xEdsCNJQFqf1YcucysQCN58+5tyBfcOo05Z6BA0lBTDCLMZXgoGXxwU8lERwpe0/i+zgAQdaQJdLoAAxicHk9FNHcwcbPZI37TAIMfR/lsEmbfR2CcT4ZSRh9MFTh3N6uCgy+DcQrTIJtURZf5MrlHAUJg5iSAJmYnVBTTPDFDACDJakTJJxtHOxsvfVNiMIzBBIrSiIbD5OHdfGFadxgZGMw2BesU97sazVq23/mwcJgcMLgZQmDJZmz3iEMkSAJe06OEVGOSNAKU8UEkSAgZIuJMSYCFkYCfda4HQTQgyGIwj8hPBxldJkAg/srKPvTxs9ra9vHXtwZ84Kjvc97fW06KFivGIpKZWaG7/dNVWVREBzf8SZGobss2fNV+OKV5+WvymqLcq6cI71BS2G8N6ESFmyLkMUjWkzDhMypOLwgSJ4gRLK0IM0WGQsSY8DLBlJHmVtxho2tkEcgJEqalD0FxpbAqPA+RkVYRE/PqoVC4bHpOwLSWyYFKFSEohzY4lku9yXli6kptsUErYhiEQIYMq+PCwpFIJf3DXrOrCbMfoEFBBCA8bDxM1nDxlbIs7c8e1/LJjB145sMo1L5sEICC4ZRrRKL16Mwltv50nKJ9MorS8aiHEryBbliampqlsUsZtkWymIiBgM0MK6TMQgEi0HAFZ65AUgy+nQ5gIbD5GaD4mR7sxQLE4JAOM702OjM9+/XK6GiTUb1/WqBYTw2GlxIluuH5AxiUQpRGA0GwUHi2CLNFwENBEmQMUhM413AyNL1FuP4H7awMInrksKEYBRiYaIiJqx9v8YwKEgYRUVQ0GIU7AsSWBCN5cc9QkEsSkt9MDRfTLHMFIks0G1pKdEyMq56QssyJnwBM7gYYhUVPJJgbBCMrXwMhklhHNMED2eEvhAUagwEyfJ35IqzBYLxHAKKKIupiXQY3GwZCdX4iKF4EgkP+ILXIFeARLKuFUZ9aJguyAOKFVqnNMGXKqMOjJnqJGAUDAWLYbRXiUVgjDJSBlgIjQgGvhwWyBfEY5y9YcbwQhRQat7kG5L51FyRQGRHwmSrlVBNpOlSGk0eWoFCo6QaqBBxhqAoLdc7EV/AFcYiZzDitgALNFtmC8iD4IwUJfgCHPp1JH3Gmoytw7wAo840CMXKyvQdD62KIowSsHidrggMplFtLT1nHOYMRlHMqZSFKoUFIoQe/TCSGnCwGOALfqbrhYTJWpc4UKDQQ6gQjLpFCbFYqTd4aIUxWFWogEJCIl88LpXaOaIgUVJkZxTDfKFRovUUmnPzhbLgBRL0sJwxgASUlDfTNTx0Lk3X2tlw+DduAiUWo6MdntMKgCExIjjclEEdBsOoN5dKh0XhQCJLFAlG6AuUEscWCc5gEvAFSskgFm4XPhAGtK4w9hnDsD7YJF7EF6MrrYbfOJ8EDGIReoPShWSMglRVjpJS88frkz/nFkpLpGLxebHIPIyF4gg6LUTI3BzddEWdARayRB7ziDVaqSjcUpoGw1LE8KzA2D7ODFOE2KJbYcwrjNE2wdib7IuSSbVF4IuFhWUqqpI+L365uvn96WmzeXfXbDaP9/fPet12q1OvlIMYMRp0WSmZE7k9OGBA3pPYuJ5qC1IWJOQxQCMHGwzjNEsINGnIH+AMpiGjST4KozrJLAqix8aCVeKrtPDw1z83y5Od1iGpReqQ6p06w7AOQ0GY5kxjqhQYnhWS/x8mwJEaIWF6YHkHUk42R4yCGcSbjsCo9PikNT+jrWee7klW1VAUmAWLYZAoPNq/7BaWiqwcRBwUhslwuCgeaVUdQb6QS2H8V0mFQ1BCsoOraciC78ytwpgYduQpCdMZn7RO5itEgkQoVGaMgsNCYHQ3T5QFJwvQMPXDcHGMuPliHPkzzmJAdzGIBWRW2OVBbXsz1wdjZVpaDJWMJnmKE4IhGIzFJIKEWZRCGBenlDpNZbDg29pPjGiMgm5OoOyMEcLhyKqqR1fcFwzES+ku3NT53yCGFAbN8E+pBV3ogyEsDEbl2K9dEIy8oAAM8QaChDAYi4XTUyPhxonJyRjmCVom2/oFijRbxK2BHV9IMAzyxrDpUmHk+2EICVPTr10SDMWRj1tDfIEgWar/cJ+L00CMOK24hkeAg0m4LDzQcFmkBojri4FiX5h+p92d7e21eixMVqBNHk3gC4hZxGGULtcAIyAR5k9MaGHKGBMgBmMsuaYmwYiV1WRjDADCLEzX6oxWP4yo7mr+zt6k0AARJFBlgYyxsLv2kDMUSKCIEZJQCHNn5FRAbQEaARCXAyt9GgEHF8VgGDsE4+n2WjsVxupqvVGj0YQ4GAnQEB4LBYIhKcOi5GR3+yLnGKPolBKnwXBw6GkqZC14gi+SYfR5glc6Aw0RfoQ6oTB5ur3d7YNRD0isrOZ1NBEUtOihJPgSGCisCuPmZu3ShTGVwgIo3HFkHCQ87TtjmzmDDgNAIpuKg29HR+QMShpnic5YFR36te3zAnInogQsyBuBMwq3O1tdaTH0ITQSYbgsaLk81BZP4skzocuiFWs4+SYiXtoswhcv6FzCZHt/KB0GdeONPwEBNKLGkD5jqUTXzkV965pBGBBCARZ0u2245k4mYQKKYGRPLCRe+jDiVhEvkxgfuvq0pzCOM3EYq0qj0uPRJEid+SQUSKEUJRcnna1rC5O4L9QafGur5QSJO6uGs1mMxsDtrOj0lUnJFmoOR3MK4/SbGAxKFyrqxn9iGHkXhioKQ1jkH0qtxg56cbDAPsYsamrCkSpy56CuE61WPwpoPLW3iGtcYTTHE5zByrfa9zyacMoAiJDGQhAmLIFxvbN0SDBAY8pJnwYCQaJdeP9B4n81nkmdVvrW3kjyoJpII3vAMPonNY+NUREY+fpdrfawPmmlFTic9MmyuaRQbDdOFEW/M+R0YBZ1RPdzsBUepgvs5CSi8FIacHuP1dFczBEg0a/MrcJYjzlDUDCNZq12KTkjHy8lhfoqw0BdXe3S0NqoO4XVhFmVjJG0gxEWEhTVUN8kZQsAAQ3BASKZCRdGGgcbW58yjK1CEoy83OSM7lEdvkC/Ndk6rBAJWqUgfbYnl4q9xosYCndHHMMZ20JhGAebU9kUgDHgsMiZUAEiAQat/9KNwlh1Yayq8qTVRq12fXLXo39xWeTbvZW+GFlaJmMUL7bOUUiSZlV1hbvRF5tH8LpBVCkkIMyoCBMnTixKErlc/sun+esmDgRhXAp+Dt4igga00hUUyBICkSboKiqe4F6AdNwLIKS42BdAigBZIjpDwR8XRDqluCoUS5FUeYObHe/YOxmT2Y3ttD/NfPvNLABjsXjcCRiEQ4+jaLfU2/Oa0dBpel9MdfAogdAaBhmrWRdQcPXEpLCbauSW1wgVCV0K2ItlEQJFi8MIEAY8ZGbI6UVZybxZGPPHdRmM0K7DGNx4Nww38VZnOGACmqxSTerJunc71LnMlqCeUi+Y18ovVEViDDEtBIsyGHff/eAAv4I6vH0YXnbI5HjNYBxLYYSw12Mztm481Kt4kxkvRMHbEus9MYDGfjYpNRh86JlbcPvHa2RoMyPXTXW9RDoBZQQrE3LjsFvVEhsOmzhwHLsMxssNg0HqCbGJol/vjdDG+vnQWOtDetLcY3AWvel0AonREzDEAJhdLtMxQlftGQSl6AXSqWBBV4JvjNBlBj4LDfWQ3A0qZTSuKOmf0ej3Yr64CBiORXiKzIwM6CBdmVUyIL/FqoRQAIwH16syGN64ExfvVBGFUE+kADgCfOE/gUWhHI570ashAXziVseHrvBciMMx+dKpQdc6AhgVBgNBZDDSyJAbh703SWEykIXr0BwMwNGP982erxc00CEeiIPGObl4yjtEJQM5IAqkocVvlQgJfqtw9/RxWzrWKBfRdzBdkBn7gMNAEhhbYy4IA3nsT7wtQRiAAlgQjU58acoGDUHQqZp7DHaQwKKmHWCoDEbNZ0GJkT2C4CBUxFNRVa0HlcnbpF2gwK9cP2WzNkEY82lVaIaLZ2PAjdNg52w11CsSKZ+9MP5oUplwwWgXeuHnhlcmQ8wMNcReVfHgRGyohJcJJoYLB+bHsWJp4OK3aKSjfpq0LYzFfFa/lhlng268gftwThyMPJz37OcwBvFL068SWGTDy0y4P94i+QQeWCY1gYGSgsPgOupDaR9vKm3wGtdqBR6edijbtgKM/hcYFINPE73mrck6TtBz/aQiKXr3XEB1/JeNPZv5OWI3p0FEuH4Os4EOshA8HAp8JfL3GEXrhsnQPsFXrcUaFuk6qGkJ/sHZOp/HHQYjzDNDGxM9LalN23xq6lcpOAuI/3Sd0WvTQBzHQfcv+Op/IfNFCfjgQxGkoi92iA+6aCMrlitqbE2wmsRlErQ2W9SA1WnNWlvFakXUFkWnU2pRZ0sdVux0jhaUTYWh6DdJY1uj31x+u8v68vvc736Xuyvbk9tTXYPEPCdxvWF0h0bn1MhBgRuBAdNLwplFHB7unOHEB3jAe0urnvaBQd/K9qTrYgIG3dUbx00Y+3xdmZUCDEdPZmePFPNWzsD9/MuGjb2jpDdjQNjOmHYfra625YIB08HRCQ0kDDcMMOgdK9RW6v+bG9gJhv/9ZcpqUTYLILLvDoFODeW1BaNrcbKsb1MXjLuA0fA66/fy7ZLFomeHqzcwttw/m9vU/aKx3hFQdHh0b2QAhvvgiAIPV76wjTO3rn6Qd++R2wYsrKu/7LFg2LHiEHFv9bT12kwZ35zFCaJjeX5ZF4ypn7PYDnY2/W69K3VPrHkIkeGAsGFMAYa9ZnVr08jIOlwopqztUFwOIJyn/f329Y8E6jDxjE+WS/1uGhYMiweIUOV1f6YXNO2jA9dL6R+9NHPGt5tTK5zs6qVWdMF4+nP29Pzdu+MWjK0P7mEXw4oNFIeGo3wexest786VGpONYjGXm261WovQR6hWa+KfKCdO7tqFsmvnrhMnE/sTJ/YnmieaM80ZS/jgs1a9Xl9aKhaLJcDyeIADxSXwGM+tpe6v3LC5F4Yjx38Lht3Cb+1waTPBE/f3Ym0Y5eVtTt7VK7ojY/bHuaONB899VsoY//C4ZEIp2dZXKsHlpfp0vf76VQ3uXkkkrly5cHh09NH1t4cjo4fimlitcDC6dEkUh9OVaiaTqWjDmcwnUdNQr2bwiGUrlcqEUSikNfKCzfJMKCRF0+KpsR37wWqmtthq1YuN+fWeLiqbJ/Ow9ynK61vpThuQ5TxMecRe2duXA8KOErdyNowPfXZkrMubs8mPD7ncuC+X8/l+Asb01Pj4ZG66vudVrfbq9avvtWazdvn8+bnP70c5pVKtVisV060Kp2taIQOhZSpdlULai2yhkhHTaTEtiiI+m0ENSiqiqCjJUSkiEJZkeZpmGJ4nBmfwNE9oejjKCxytMVpI06SMBLNz/5Xm948f60sAU29Y8fIcpn9Nnur7v8p5e4C4LvvHX9FRPG7CuPY4782vpfpWeq3vgV69urCwMLfwZu793NzXX7s/PzTdgycTlQrLvoAYTRuWwoqBfhyOKEHFr4hKXJIUMewPhIMDQ9t3nhoa2jEQlRiNDTGhsWAwMCgEAnsvyrIcjUYCg4ODYzFBQEUmMVnNxrJqzFQ2a/AsT8dUgZYFggfCAZWnjVj0YkwlsZRwKSrL0rARSyRmFp+1akvzI/3960seB4c7Qp567TBxcmqP6ahdb9gwTvcvp9bmJ4v2MdTCwh3wqH76BAboVDGcVKRw4FKU0cQJXZMYMRwQ40o4DBMJjiYfmUqnFX88HI+HD/v9QX8kMixJ+LAoMgwTkkMxNaWCAzxU4bwKZ0OCLMRiaBFVJrIqqwJDCwbJEkHmOY7VWRYUDEMViMzLIcKzLMdxNANSjCHwKgDGSCp15kxz5mMNeak17xmhPOv/xvK01DmJxd2TNRwKbTLIIvMmDCxOPGaS9eT6LBjxZPL69etDY2Po0mAY3TgA1wehoF+JDATwOBDc5t+GOAcqJZ02WVgS0UyKGAIaCgaNrrHshK5zPGPQWZoQdH1WJQKtyrQgEGIwHENQi2pRgaYFFUwIkWUAydI0YWgMGYYhBMGTSmVlAvEEDzW9MKEX9AIsh7GVUlMpwD6xo3nsQnNxsTg/YiaUNgxfzwIfOBwgZukJEOTUERzDY9lq/e3HZdTddRaMY9sOHU4q/gDcTsZF/6kDB7eHlahw4OLYUDodDg0EAv64EvcHIsmkiBSgiUkTgw0DRRIruq4x6EyW4Tid1V/oOsvrBpoG4QxCaI5nOZoYAqEJAkKmaVoVZBlRIsgInd9knN1r+2QUx3+g/5O3ghdeeOe1DzEJyZP6RBIS+kDTJWmbaJumc7VNmqaMTrbadl2dVSeKDJnCNkGssImK4gYiCL7zQ3xH/aa+XXj6nrRJzud8z/ckN10m5SRbrYAJn7LOQtM1bKZWLXf0YuVymZbLYFVsZAwuRWAHmpYs8xyrk1zdh63BXra3P3gLvvKfUP4h8f+Ae+AvmQoYUMarmxP7t969p4ChYPa1mZfmlmIM4AOpaZLBcy0exx5haJkRlE9ds5MlGe3y0dFZtVYdQQ0wxepohGpVj7AEt+JpXLwebaBUR9XxeHyEJUXV9SbXdTjnYtM3Tb3ebDY5+GQQEcSRZbAk8AKzDBar16rV0Xis4ydJh/Nm0XDNBF5b08HkXyLVqlZYcLO5TBItNIT+wfEnn3+Nkf1L4bxfbD+0/RDoINki+78t9F8/fejpTZ88+shm/ZvbD4LGHbEkSJP5fNClJJfnscfM6elWPBot9JwqNBrVdbhZtiqv1uvlUtPLo9r1de0a5hdyXisUsVhoGt5cb6JWmG5dw3f0GvBEUbOua4hOvsQh15MyOABNXV9mZaSoIUdUv9PJ6qCgwTjwVC5DN00NN6SuhRg9EdowwlY4FKUVUDv1+gJUqijEGGBqWr2GxRlUuNCK6qAYrZAaan8fNvP9OxhLYLN9H8gg9Y3B3nvfa3/BeHbTWq/f/zCW3pm3B8wfPP/cZTAYBEaEIVieJtMIO8jyZJrzUX2xqunZarGoAYy2wjtIFjxQxmIywiL0Mrq9OtKBhGudMMbdpKEZovML69S5XuZc13ALm5yXeRTGmteNIg5xYFZhPWQSavVNnhnshKadhJhL2knwwng0Ho2PRmOMXt0LOb6ddJIMuPALxKJWh09VoRb4bhkbgUIRQHU0rm4kC2mOqnWa93tfff45TmV++eUzoPlocw3/+Mubznr9vgfuAwwY4vz2u8t58ToYnFw+143CpUNacHi9kzjTZsj1arm+WqxQxRXaos7LnUX1GsOgeED+PMQ8iTFVbJd5DMZrIohNKO3EISYT8yLTNW3XY9EcPhy7LiPeYH7pxhhSns3ibux29WjEaexyHkeeaWITnunhU4fmy5xS0/NIqPOo1YriWAtNF7vjsRt7sd3pNOuYzRs2dahtsdBXcGtIBTzOjs7gM2fjjVbACPrRkYEWG8bh008DxiuPv/3Gu+im9x+8dxt/QPTzxcXF7cXF1e3t1dwPBs893+qaNkoUomY8SdZLZ9nBFlBk2EcYVjmfcbOoXZgB02LmzcJYZEaqUoFIRBRO/MCzbZO4Q+YOGDNtO3AH3e6QnQSC4Q9PuicDPxAF8epKFAWDCWIQqAax0Z/oUIpb7HkCs21i2JRyxgg1YOKGQfAlkxPXG3Qjj9lUNQyBEcGTmEF2FEJ3wiSd5tMscZylczo9hblmzUUdEM6KgE7QULUxpKSPa2eto+ixp18pYLz3493j9vHhx1+/88YXd47vHh5eHNzeXl7efncyHN5ezrvzgasnK946O4s0dIiWzeJuFDcCz6R5wwxDHBdzPTPkkcuYy7pmimN1TVNCjrIgE9uFRgR/iL5DCIFkKL7vBwHusmTIclsWbV/0BcNQDckQDaRlCIIvBMwDCaRtScQEECA1DZfZnqdKqtovSSW1ryD6SkUtKf2eqqiqofYk26O55ZQ5ofnWspm/tOU4adKcOs506UynWTlbadUjaOTDs7/jCGBGHz/1w6+vvPjkez/9cSG05i1MTOHO8eHk4ArR9qVS22hPJm4cufNWqGucR9GoFg1aeiwKskxAn+bUnJmi74kBG3h2EJwIgh15rtGQfFsQCRIN/JM5ugErsPakHaD+QCRJ/b5i7TQkxZLkRkMRjZyoRBRFqVQgMUqqYCAzM9ZDklJCIBEKygSLWhCaJEkK0u/3Kz1c8vWtUq/S6/UUlaIOBMhc4nXCNKe5smNt7VYsB921tbtlOZ9+Oz3d+/b0/ObmZn1TOD8MHudC4HL042O/v/Dii09+8PHxYV8y4xYuHu6U9iclVT6eoKKK5LGYoP/DMJYCdKwHMKEkEjrLrQbhGaUpITMz78uuJKGU/gS5B+4QfTBs+7d4CD464Wo4FE4QoixLvi/KogeSSoUqPLYsmzTSBiGoOkEK2F6qKISgKZAypTNKc9ODxcQMRkFEj7E4CJiAC7mK1QMJpbffw6uyXyn1VckzbaYW8oTVcN3z+LQ41K2tPcfZ3XIsZ+/0fG/vm7/i/PwbAPnmm5ubD6/Bpl7A+OGVJ788vnv3sLQ8d/Z29++gZJIk44lFEdsUng6i7mB4NXC5XJLT2c6Okq6nllJxQN1SULhZmgKJeCD77at22w8mpbbQbh+0EX5bECcHk6EkqxJQxA3SkAVGp7Nwna3WsygK17OZHdo0TRuUpAzYZ7RhpyBjwxkIQKR5TonnNgonFg3FEBAGIR54Yv9WBQqBStAoPUmlrs0II+7ApTZwRLoWlXHKn0ydffDqOad75zffFvlfj6/PVx/W1muaTvd2G5+efnv+8TO//f5EAaN7cffC4GXMhjs7DSUObTEQPM5DGrMoJD5jgtw/KFlIv2dN16egvPvS7kv7+8q+Y1lOTsO0VJJVuT85UFW1UpqUwFOA5EsVUfRUS1LkgKZOXuS8tnbSMKTT5XKxmDlpGsKGsTgOKSeKjVEZzjCNbEpyQySYOS4kY+WWoQQ2EVXVNCoVVWYkkFKq5DuWAveAeSDgGQIxDAmSQq/+2YP1vSoNBeD+0THODpuMBZMzErZmq81KZ3Bk5poxGrnhtN+k9GTQi/rmg70UWYESGERKIRQR9R2Dzu1e72b33p3vfL/OuWJ0LKuNMLp5887tS3fgFgw6cQ+A4jyuvv7QfMqHD2oV7mxdl73fvr/+6ff95zdevL9qfDt6dx827z2+0KrVKuWqVzK/dfVqi5g18Na3VWcwGUTuUIAAeGcwItd13DRyXW5HgrL4nmJx8L2tKhhSuywvlrd6WqAAKF+sr+84fb4SRsYdvlqBE7xXazwr27VqoyzRNjhWtYr4jbH9hTBIX7Ka9XoLCEk9pqoAWINXRBHzFY2plT7vMR9v2AoBGFq4Pp12a9XEEVLXNAn4Y8VVw6zcqt659ah6ayg9kmAYMxdamR8O8/klPhqhPz99GrDs6+rw5ZcYP959mfuLcTEp+UC90Chr/crVB2XN6KDoGQokzRnmPJmkkeO4TjZx4D9zN3vEOa4HwIRHAzcdOK5LfM2Hag0QmKJNoEe9ulcDK4hsVB01kWoVh0ucP7uzGg5X2AJWiNUor12qqIRIQiaSRa0qleUkEJ1DkgOZmhKmpEiGBQfzBcoq/BWOS/t4LAlpVqlqqt1lWnHaf95/BBdhq3mY63Ls6WECz4pHsgzvrcoxqo9kBB+Xu93nzxscVGxefv/+9u33l5+Xd98+bb79jo36W/zDx/mMZvT0AhBoBnGnVq+PRu22gZ2KxNxJ6qYZEipDNcfIPgwd1xcLHKWuPci47bhsxTlj5pUrDWq12oaXJNWK1Ea/oRCrrTHGwG8XP+Lw8tFqyMGLILAIDeqNmo90CaEl3aY0oR4hGjE6QSeA1BIJPkGphpseLnVoAkF+RVEqcFRwRbIs4n08Ynq7n3lXI+ZZMnkRml6o53mIvrQo1h8X68Vx/3nzEscT57HBec3u58/FWNO74PUjPE+t3ey8Egdv4rwKr817by7UW61WPUwIHYU55b6bpmk2cbMMCz90M1y6LB2krMcGzGd2OhhEUJGLtOdl7YpvytYo9qadekKIVTUQALzPXbtrgys+Y/g/JV9BKjCGOwxz1CiiNiCKbUfdaNAFwXWFQlZQPpnKHvWSQNBAowHWGJF8DmbTVENyBW0DzkaWYMTLzX5dKNh6UJHKuvg1+PIkH4/zxfH487TffBcwvHz5crPZ7U4f1x7yLZapbOpEicyKEFynLfV4X3FmZb/S03wEu0QuiNS3bVAS9gsg5rMMspjNRDQ5g8HgizvoQzKTAYNJTNyJy6IvOqLNp9ACXDwJQ1S16XRZJ0GRVAMdMOjMh5PoPnfQLPDBazBMoyldoRSzCQCJ31NBHB/piMfU8JsMS2bUkxFHRPGJBljkRBNoaJoMQGxh0PVRstx/xyrvFqCAJyuhTnXUNsX01uF68fO4P3NBQAC09rsjiADyaCEqW99UCEJfJpYRJIBRTojVbo6u2CqiXOpLjji3iS/ojDv2wIYuMJz5/EPmpFmWifTY4hh7ghFFACN1YamQjIOgHyCN9WnhoVnFRMFze5ROExpG8DoAqKM22T7TqE96PSR/ULZjA47RbrYqDcXoEFK2rlC5VamjzBFNkTXBBCo+u5CHAn9UiWwpoBGmIKtyWOBvfTx9Fqv9+bjAziEvijBcfBRZvvi522+EIPDmd8jh9PPPt295XozRqlH8TaCmoNipehexj4HYj+EJ03rcXD7G0d3TxxIOMuuGeaV+IWLOBCN1EMnb4Tybn0WSHbbvt2IAjTMi2zSdnCWEVGEqpKxpEKlK1FpDUkWmwifsCEBRTM+gvmRxlfg4J7Kahk4QGrDEdqXRaOgq1NaTdPijRCvY0OAHsO6qZqOYsAjQKCxKqB54no2Vp0WRY94wiTMnjovjugjX4/H4Sb5YwBk3Z1cAGT7vTsef38Y5jq+fjPGCT/AHWwJpuvamAAQVVxEkDGLZwCIGONdPAmuEL6N4WU9kLUgupOAAlDFbrWYrBFE2SdP3k+32cDhkGV7T9wBjO8sEWCvHzYarizBOJUS7VuUAW4S+0EQaqSr4oukMAvIraAPVhkQbJTyF6qoGQ4Gq/bKH9NHRDBmHc3KqyqKjInyC0PO1iKm+Yiu23xepyjSddqlSaDkEsN9gwuDEN9hCAW+EM5xw7z8MggvfgI9wjQLjHyJnD8HVVIamTISvKUFUZzNKgmUSL+PHMY48vcfJR3RMUSAvbCczaGM+nH2YHQ5CGdtsm4ElXw/bSZYBkjTF1XA4Sx+JqnCnN/QZHhcswLQpKnKK+gFtuERlmA76ZZ8ElkZoXMXZiCGH0H+QEBDHR4mDzmzOG6ruUzDCklHXhZ9qCrEj3UaTkXzfjwlTFNClwMDyb4Q6NrufTzDFRbE4QRX/RIGbp8UZgicYeBMAdItxNwQkuIm73Sdd+GsuCjLgwF/SiUljWQ/DJf2YgDajUTINPQAzXcfT0QVUqrloJVDILNtucYWXGco7rme4mWWoGM8eDR89G/KbDy7fewZHRB0HrW2U/9JNEZ8MbcjJWIVbRqtTsooMT8UOvtNpGxB94YXwZ9UOVNQWeA9SqatGrm1TseXAFg3y8P2Iwbd4z+E99BmUbswierKAT2BsTt/Os8UlfAMDBgkcivU68XTtCXZa+ZNC6OlJN0ftGBfj8yhAE1Nsd70wR2qZoaJosqaqXm4CHgxk8Gi0lr3pdPR4OfI+/gWlmQYG2RA5CAAAAABJRU5ErkJggg==\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Direction\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.7227918773301678,\"funcBody\":\"if (prevValue === 0) {\\n prevValue = Math.random() * 360;\\n}\\nvar value = prevValue + Math.random() * 20 - 10;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 360) {\\n\\tvalue = 360;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Wind Speed\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 16 - 8;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 26) {\\n\\tvalue = 26;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"m/s\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"layout\":\"default\",\"centerValueFont\":{\"family\":\"Roboto\",\"size\":24,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"centerValueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0.2,\"color\":\"#6083EC\"},{\"from\":0.2,\"to\":3.4,\"color\":\"#5579E5\"},{\"from\":3.4,\"to\":8,\"color\":\"#4369DD\"},{\"from\":8,\"to\":10.8,\"color\":\"#2B54CE\"},{\"from\":10.8,\"to\":17.2,\"color\":\"#224AC2\"},{\"from\":17.2,\"to\":24.5,\"color\":\"#F04022\"},{\"from\":24.5,\"to\":null,\"color\":\"#DE2343\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"ticksColor\":\"rgba(0, 0, 0, 0.12)\",\"directionalNamesElseDegrees\":true,\"majorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"majorTicksColor\":\"rgba(158, 158, 158, 1)\",\"minorTicksFont\":{\"family\":\"Roboto\",\"size\":14,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"20px\"},\"minorTicksColor\":\"rgba(0, 0, 0, 0.12)\",\"arrowColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Wind Speed\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{\"headerButton\":[]},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":true,\"titleTooltip\":\"\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"titleIcon\":\"mdi:windsock\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"24px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null},\"titleColor\":\"rgba(0, 0, 0, 0.87)\"}" }, "externalId": null, "tags": [ diff --git a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts index 45344aba84..6bf8c38e59 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/config/basic/weather/wind-speed-direction-basic-config.component.ts @@ -34,15 +34,8 @@ import { setTimewindowConfig } from '@home/components/widget/config/timewindow-config-panel.component'; import { formatValue, isDefinedAndNotNull, isUndefined } from '@core/utils'; +import { cssSizeToStrSize, getDataKey, resolveCssSize, updateDataKeys } from '@shared/models/widget-settings.models'; import { - cssSizeToStrSize, getDataKey, - getDataKeyByLabel, - resolveCssSize, - updateDataKeyByLabel -} from '@shared/models/widget-settings.models'; -import { - centerValueLabel, - windDirectionLabel, windSpeedDirectionDefaultSettings, WindSpeedDirectionLayout, windSpeedDirectionLayoutImages, @@ -108,25 +101,21 @@ export class WindSpeedDirectionBasicConfigComponent extends BasicWidgetConfigCom } protected defaultDataKeys(configData: WidgetConfigComponentData): DataKey[] { - return [{ name: 'winddirection', label: windDirectionLabel, type: DataKeyType.timeseries }, - { name: 'windspeed', label: centerValueLabel, type: DataKeyType.timeseries, + return [{ name: 'direction', label: 'Wind Direction', type: DataKeyType.timeseries }, + { name: 'speed', label: 'Wind Speed', type: DataKeyType.timeseries, units: 'm/s', decimals: 1 }]; } protected onConfigSet(configData: WidgetConfigComponentData) { const settings: WindSpeedDirectionWidgetSettings = {...windSpeedDirectionDefaultSettings, ...(configData.config.settings || {})}; const iconSize = resolveCssSize(configData.config.iconSize); - let windDirectionDataKey = getDataKeyByLabel(configData.config.datasources, windDirectionLabel); - if (!windDirectionDataKey) { - windDirectionDataKey = getDataKey(configData.config.datasources); - } this.windSpeedDirectionWidgetConfigForm = this.fb.group({ timewindowConfig: [getTimewindowConfig(configData.config), []], datasources: [configData.config.datasources, []], - windDirectionKey: [windDirectionDataKey, [Validators.required]], + windDirectionKey: [getDataKey(configData.config.datasources, 0), [Validators.required]], - centerValueKey: [getDataKeyByLabel(configData.config.datasources, centerValueLabel), []], + centerValueKey: [getDataKey(configData.config.datasources, 1), []], centerValueFont: [settings.centerValueFont, []], centerValueColor: [settings.centerValueColor, []], @@ -167,8 +156,15 @@ export class WindSpeedDirectionBasicConfigComponent extends BasicWidgetConfigCom setTimewindowConfig(this.widgetConfig.config, config.timewindowConfig); this.widgetConfig.config.datasources = config.datasources; - updateDataKeyByLabel(this.widgetConfig.config.datasources, config.windDirectionKey, windDirectionLabel); - updateDataKeyByLabel(this.widgetConfig.config.datasources, config.centerValueKey, centerValueLabel); + const dataKeys: DataKey[] = []; + if (config.windDirectionKey) { + dataKeys.push(config.windDirectionKey); + if (config.centerValueKey) { + dataKeys.push(config.centerValueKey); + } + } + + updateDataKeys(this.widgetConfig.config.datasources, dataKeys); this.widgetConfig.config.showTitle = config.showTitle; this.widgetConfig.config.title = config.title; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts index a9ae8b978a..aa33842cb9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/weather/wind-speed-direction-widget-settings.component.ts @@ -21,14 +21,13 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { formatValue, isDefinedAndNotNull } from '@core/utils'; import { - centerValueLabel, windSpeedDirectionDefaultSettings, WindSpeedDirectionLayout, windSpeedDirectionLayoutImages, windSpeedDirectionLayouts, windSpeedDirectionLayoutTranslations } from '@home/components/widget/lib/weather/wind-speed-direction-widget.models'; -import { getDataKeyByLabel } from '@shared/models/widget-settings.models'; +import { getDataKey } from '@shared/models/widget-settings.models'; @Component({ selector: 'tb-wind-speed-direction-widget-settings', @@ -38,7 +37,7 @@ import { getDataKeyByLabel } from '@shared/models/widget-settings.models'; export class WindSpeedDirectionWidgetSettingsComponent extends WidgetSettingsComponent { get hasCenterValue(): boolean { - return !!getDataKeyByLabel(this.widgetConfig.config.datasources, centerValueLabel); + return !!getDataKey(this.widgetConfig.config.datasources, 1); } get majorTicksFontEnabled(): boolean { @@ -120,7 +119,7 @@ export class WindSpeedDirectionWidgetSettingsComponent extends WidgetSettingsCom } private _centerValuePreviewFn(): string { - const centerValueDataKey = getDataKeyByLabel(this.widgetConfig.config.datasources, centerValueLabel); + const centerValueDataKey = getDataKey(this.widgetConfig.config.datasources, 1); if (centerValueDataKey) { let units: string = this.widgetConfig.config.units; let decimals: number = this.widgetConfig.config.decimals; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts index d328e59ace..3e341d11f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts @@ -24,12 +24,11 @@ import { OnInit, Renderer2, TemplateRef, - ViewChild, ViewEncapsulation + ViewChild, + ViewEncapsulation } from '@angular/core'; import { WidgetContext } from '@home/models/widget-component.models'; import { - centerValueLabel, - windDirectionLabel, windSpeedDirectionDefaultSettings, WindSpeedDirectionLayout, WindSpeedDirectionWidgetSettings @@ -38,8 +37,8 @@ import { backgroundStyle, ColorProcessor, ComponentStyle, - Font, getDataKey, - getDataKeyByLabel, + Font, + getDataKey, getSingleTsValueByDataKey, overlayStyle } from '@shared/models/widget-settings.models'; @@ -118,11 +117,8 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft this.ctx.$scope.windSpeedDirectionWidget = this; this.settings = {...windSpeedDirectionDefaultSettings, ...this.ctx.settings}; - this.windDirectionDataKey = getDataKeyByLabel(this.ctx.datasources, windDirectionLabel); - if (!this.windDirectionDataKey) { - this.windDirectionDataKey = getDataKey(this.ctx.datasources); - } - this.centerValueDataKey = getDataKeyByLabel(this.ctx.datasources, centerValueLabel); + this.windDirectionDataKey = getDataKey(this.ctx.datasources, 0); + this.centerValueDataKey = getDataKey(this.ctx.datasources, 1); if (this.centerValueDataKey) { this.decimals = this.ctx.decimals; @@ -169,21 +165,27 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft } public onDataUpdated() { - let centerValue = 0; + let value = 0; this.windDirection = 0; this.centerValueText = 'N/A'; - const windDirectionTsValue = getSingleTsValueByDataKey(this.ctx.data, this.windDirectionDataKey); - if (windDirectionTsValue && isDefinedAndNotNull(windDirectionTsValue[1]) && isNumeric(windDirectionTsValue[1])) { - this.windDirection = windDirectionTsValue[1]; + if (this.windDirectionDataKey) { + const windDirectionTsValue = getSingleTsValueByDataKey(this.ctx.data, this.windDirectionDataKey); + if (windDirectionTsValue && isDefinedAndNotNull(windDirectionTsValue[1]) && isNumeric(windDirectionTsValue[1])) { + this.windDirection = windDirectionTsValue[1]; + if (!this.centerValueDataKey) { + value = this.windDirection; + this.centerValueText = formatValue(value, 0, '') + '°'; + } + } } if (this.centerValueDataKey) { const centerValueTsValue = getSingleTsValueByDataKey(this.ctx.data, this.centerValueDataKey); if (centerValueTsValue && isDefinedAndNotNull(centerValueTsValue[1]) && isNumeric(centerValueTsValue[1])) { - centerValue = centerValueTsValue[1]; - this.centerValueText = formatValue(centerValue, this.decimals, '', true); + value = centerValueTsValue[1]; + this.centerValueText = formatValue(value, this.decimals, '', true); } } - this.centerValueColor.update(centerValue); + this.centerValueColor.update(value); this.renderValues(); } @@ -313,9 +315,8 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft } private renderCenterValueText() { - const text = this.centerValueDataKey ? this.centerValueText : formatValue(this.windDirection, 0, '') + '°'; this.centerValueTextNode.text(add => { - add.tspan(text).font({size: '24px'}); + add.tspan(this.centerValueText).font({size: '24px'}); if (this.units) { add.tspan(this.units).newLine().font({size: '14px'}); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts index c9fe2a84df..6359696f25 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.models.ts @@ -103,6 +103,3 @@ export const windSpeedDirectionDefaultSettings: WindSpeedDirectionWidgetSettings } } }; - -export const windDirectionLabel = 'windDirection'; -export const centerValueLabel = 'centerValue'; diff --git a/ui-ngx/src/app/shared/models/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts index 056738f396..5055893b6f 100644 --- a/ui-ngx/src/app/shared/models/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -422,16 +422,23 @@ export const overlayStyle = (overlay: OverlaySettings): ComponentStyle => ( } ); -export const getDataKey = (datasources?: Datasource[]): DataKey => { +export const getDataKey = (datasources?: Datasource[], index = 0): DataKey => { if (datasources && datasources.length) { const dataKeys = datasources[0].dataKeys; - if (dataKeys && dataKeys.length) { - return dataKeys[0]; + if (dataKeys && dataKeys.length > index) { + return dataKeys[index]; } } return null; }; +export const updateDataKeys = (datasources: Datasource[], dataKeys: DataKey[]): void => { + if (datasources && datasources.length) { + datasources[0].dataKeys = dataKeys; + } +}; + + export const getDataKeyByLabel = (datasources: Datasource[], label: string): DataKey => { if (datasources && datasources.length) { const dataKeys = datasources[0].dataKeys; From 408b890679a66f61a67a53b092eb29ea651dc6d1 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 20 Oct 2023 11:01:04 +0300 Subject: [PATCH 227/267] UI: Fixed widget setting boarder radius --- .../src/app/modules/home/models/dashboard-component.models.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 8104e80e36..790ea29615 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -479,7 +479,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { backgroundColor: this.backgroundColor, padding: this.padding, margin: this.margin, - borderRadius: this.borderRadius}; + borderRadius: this.borderRadius || 'unset' }; if (this.widget.config.widgetStyle) { this.style = {...this.style, ...this.widget.config.widgetStyle}; } From fc1d694fd77dc51866246ee3d25a6784a11db831 Mon Sep 17 00:00:00 2001 From: rusikv Date: Fri, 20 Oct 2023 11:13:43 +0300 Subject: [PATCH 228/267] UI: Fixed state chart default legend position not set --- .../src/main/data/json/system/widget_types/state_chart.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/data/json/system/widget_types/state_chart.json b/application/src/main/data/json/system/widget_types/state_chart.json index 25a3130d48..a78fc06f64 100644 --- a/application/src/main/data/json/system/widget_types/state_chart.json +++ b/application/src/main/data/json/system/widget_types/state_chart.json @@ -19,7 +19,7 @@ "latestDataKeySettingsDirective": "tb-flot-latest-key-settings", "hasBasicMode": true, "basicModeDirective": "tb-flot-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"legendConfig\":{\"direction\":\"column\",\",position\":\"bottom\",\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"waterfall_chart\",\"iconColor\":\"#1F6BDD\"}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 1\",\"color\":\"#2196f3\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false,\"axisPosition\":\"left\",\"showSeparateAxis\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"return Math.random() > 0.5 ? 1 : 0;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Switch 2\",\"color\":\"#ffc107\",\"settings\":{\"showLines\":true,\"fillLines\":false,\"showPoints\":false,\"axisPosition\":\"left\"},\"_hash\":0.12775350966079668,\"funcBody\":\"return Math.random() <= 0.5 ? 1 : 0;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"tooltipValueFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\",\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":0,\"max\":1.2,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"if (value > 0 && value <= 1) {\\n return 'On';\\n} else if (value === 0) {\\n return 'Off';\\n} else {\\n return '';\\n}\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"timeForComparison\":\"previousInterval\",\"comparisonCustomIntervalValue\":7200000,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"right\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":false,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"dataKeysListForLabels\":[]},\"title\":\"State Chart\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"widgetStyle\":{},\"useDashboardTimewindow\":true,\"showLegend\":true,\"actions\":{},\"configMode\":\"basic\",\"showTitleIcon\":false,\"titleIcon\":\"waterfall_chart\",\"iconColor\":\"#1F6BDD\"}" }, "externalId": null, "tags": null From a47ceaafedfe34be9e50fdb63e8f854536d97f6a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 20 Oct 2023 13:06:02 +0300 Subject: [PATCH 229/267] UI: Improve widgets value formatting. --- .../widget/lib/cards/progress-bar-widget.component.ts | 2 +- .../widget/lib/cards/value-card-widget.component.ts | 2 +- .../widget/lib/cards/value-chart-card-widget.component.ts | 2 +- .../widget/lib/indicator/battery-level-widget.component.ts | 2 +- .../widget/lib/indicator/signal-strength-widget.component.ts | 2 +- .../lib/weather/wind-speed-direction-widget.component.ts | 4 ++-- 6 files changed, 7 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts index 22d3cb6f4d..2b9d4328d5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts @@ -174,7 +174,7 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI this.value = 0; if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { this.value = tsValue[1]; - this.valueText = formatValue(this.value, this.decimals, this.units, true); + this.valueText = formatValue(this.value, this.decimals, this.units, false); } else { this.valueText = 'N/A'; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index d723b9b472..75a922daff 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -182,7 +182,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro if (tsValue) { ts = tsValue[0]; value = tsValue[1]; - this.valueText = formatValue(value, this.decimals, this.units, true); + this.valueText = formatValue(value, this.decimals, this.units, false); } else { this.valueText = 'N/A'; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts index 7cd58e3c13..ce5b61943c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts @@ -194,7 +194,7 @@ export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnD let value; if (tsValue) { value = tsValue[1]; - this.valueText = formatValue(value, this.decimals, this.units, true); + this.valueText = formatValue(value, this.decimals, this.units, false); } else { this.valueText = 'N/A'; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts index a2793234f4..a983dc81a9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts @@ -224,7 +224,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView this.value = 0; if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { this.value = tsValue[1]; - this.valueText = formatValue(this.value, this.decimals, this.units, true); + this.valueText = formatValue(this.value, this.decimals, this.units, false); } else { this.valueText = 'N/A'; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts index 5891f2b297..10ba3b3b1b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts @@ -232,7 +232,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi if (!this.noData) { this.rssi = Number(value); if (this.showTooltipValue) { - this.tooltipValueText = formatValue(value, this.decimals, this.units, true); + this.tooltipValueText = formatValue(value, this.decimals, this.units, false); } } else { this.rssi = -100; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts index 3e341d11f5..bf43218f82 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/weather/wind-speed-direction-widget.component.ts @@ -174,7 +174,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft this.windDirection = windDirectionTsValue[1]; if (!this.centerValueDataKey) { value = this.windDirection; - this.centerValueText = formatValue(value, 0, '') + '°'; + this.centerValueText = formatValue(value, 0, '', false) + '°'; } } } @@ -182,7 +182,7 @@ export class WindSpeedDirectionWidgetComponent implements OnInit, OnDestroy, Aft const centerValueTsValue = getSingleTsValueByDataKey(this.ctx.data, this.centerValueDataKey); if (centerValueTsValue && isDefinedAndNotNull(centerValueTsValue[1]) && isNumeric(centerValueTsValue[1])) { value = centerValueTsValue[1]; - this.centerValueText = formatValue(value, this.decimals, '', true); + this.centerValueText = formatValue(value, this.decimals, '', false); } } this.centerValueColor.update(value); From 23cd7f08654fddf66b6d3fa7f882f0e0ce50e336 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 20 Oct 2023 15:03:24 +0300 Subject: [PATCH 230/267] Fix testNotificationRuleProcessing_exceededRateLimits --- .../notification/NotificationRuleApiTest.java | 27 +++++++++++-------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java index 0a2854a28d..33aaf2af35 100644 --- a/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java +++ b/application/src/test/java/org/thingsboard/server/service/notification/NotificationRuleApiTest.java @@ -420,11 +420,11 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { notificationRulesCache.evict(TenantId.SYS_TENANT_ID); int n = 10; - updateDefaultTenantProfile(profileConfiguration -> { - profileConfiguration.getProfileConfiguration().get().setTenantEntityExportRateLimit(n + ":600"); - profileConfiguration.getProfileConfiguration().get().setCustomerServerRestLimitsConfiguration(n + ":600"); - profileConfiguration.getProfileConfiguration().get().setTenantNotificationRequestsPerRuleRateLimit(n + ":600"); - profileConfiguration.getProfileConfiguration().get().setTransportDeviceTelemetryMsgRateLimit(n + ":600"); + updateDefaultTenantProfileConfig(profileConfiguration -> { + profileConfiguration.setTenantEntityExportRateLimit(n + ":600"); + profileConfiguration.setCustomerServerRestLimitsConfiguration(n + ":600"); + profileConfiguration.setTenantNotificationRequestsPerRuleRateLimit(n + ":600"); + profileConfiguration.setTransportDeviceTelemetryMsgRateLimit(n + ":600"); }); loginTenantAdmin(); NotificationRule rule = createNotificationRule(AlarmCommentNotificationRuleTriggerConfig.builder() @@ -434,11 +434,14 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { rateLimitService.checkRateLimit(LimitedApi.ENTITY_EXPORT, tenantId); rateLimitService.checkRateLimit(LimitedApi.REST_REQUESTS_PER_CUSTOMER, tenantId, customerId); rateLimitService.checkRateLimit(LimitedApi.NOTIFICATION_REQUESTS_PER_RULE, tenantId, rule.getId()); + Thread.sleep(100); } loginTenantAdmin(); - List notifications = await().atMost(30, TimeUnit.SECONDS) - .until(() -> getMyNotifications(true, 10), list -> list.size() == 3); + List notifications = await().atMost(15, TimeUnit.SECONDS) + .until(() -> getMyNotifications(true, 10).stream() + .filter(notification -> notification.getType() == NotificationType.RATE_LIMITS) + .collect(Collectors.toList()), list -> list.size() == 3); assertThat(notifications).allSatisfy(notification -> { assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded"); }); @@ -455,12 +458,14 @@ public class NotificationRuleApiTest extends AbstractNotificationApiTest { }); loginSysAdmin(); - notifications = await().atMost(30, TimeUnit.SECONDS) - .until(() -> getMyNotifications(true, 10), list -> list.size() == 1); - assertThat(notifications).allSatisfy(notification -> { + notifications = await().atMost(15, TimeUnit.SECONDS) + .until(() -> getMyNotifications(true, 10).stream() + .filter(notification -> notification.getType() == NotificationType.RATE_LIMITS) + .collect(Collectors.toList()), list -> list.size() == 1); + assertThat(notifications).singleElement().satisfies(notification -> { assertThat(notification.getSubject()).isEqualTo("Rate limits exceeded for tenant " + TEST_TENANT_NAME); + assertThat(notification.getText()).isEqualTo("Rate limits for entity version creation exceeded"); }); - assertThat(notifications.get(0).getText()).isEqualTo("Rate limits for entity version creation exceeded"); } @Test From aea4d267ffebaa8dca0ffe4b11a1336a4cb35df3 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 20 Oct 2023 15:26:25 +0300 Subject: [PATCH 231/267] Minor improvements --- .../queue/ruleengine/TbRuleEngineConsumerContext.java | 3 ++- .../home/components/profile/tenant-profile.component.ts | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java index b18df6b62b..da2a5d0db4 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineConsumerContext.java @@ -19,6 +19,7 @@ import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; +import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.common.util.ThingsBoardThreadFactory; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.common.stats.StatsFactory; @@ -76,7 +77,7 @@ public class TbRuleEngineConsumerContext { @PostConstruct void init() { this.consumersExecutor = Executors.newCachedThreadPool(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer")); - this.mgmtExecutor = Executors.newFixedThreadPool(mgmtThreadPoolSize, ThingsBoardThreadFactory.forName("tb-rule-engine-mgmt")); + this.mgmtExecutor = ThingsBoardExecutors.newWorkStealingPool(mgmtThreadPoolSize, "tb-rule-engine-mgmt"); this.scheduler = Executors.newSingleThreadScheduledExecutor(ThingsBoardThreadFactory.forName("tb-rule-engine-consumer-scheduler")); } diff --git a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts index 26d6611a3c..3f048ab2e3 100644 --- a/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts +++ b/ui-ngx/src/app/modules/home/components/profile/tenant-profile.component.ts @@ -56,7 +56,7 @@ export class TenantProfileComponent extends EntityComponent { const mainQueue = [ { id: guid(), - consumerPerPartition: true, + consumerPerPartition: false, name: 'Main', packProcessingTimeout: 10000, partitions: 1, @@ -84,7 +84,7 @@ export class TenantProfileComponent extends EntityComponent { topic: 'tb_rule_engine.hp', pollInterval: 2000, partitions: 1, - consumerPerPartition: true, + consumerPerPartition: false, packProcessingTimeout: 10000, submitStrategy: { type: 'BURST', @@ -108,7 +108,7 @@ export class TenantProfileComponent extends EntityComponent { topic: 'tb_rule_engine.sq', pollInterval: 2000, partitions: 1, - consumerPerPartition: true, + consumerPerPartition: false, packProcessingTimeout: 10000, submitStrategy: { type: 'SEQUENTIAL_BY_ORIGINATOR', From 857256a9fe6b96c3275589494c5d2a440e2c1abb Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 20 Oct 2023 15:26:50 +0300 Subject: [PATCH 232/267] UI: Outdoor Environment: Rainfall widgets. --- .../widget_bundles/outdoor_environment.json | 10 +++++- .../horizontal_rainfall_card.json | 29 +++++++++++++++++ ...izontal_rainfall_card_with_background.json | 29 +++++++++++++++++ .../system/widget_types/rainfall_card.json | 29 +++++++++++++++++ .../rainfall_card_with_background.json | 29 +++++++++++++++++ .../widget_types/rainfall_chart_card.json | 32 +++++++++++++++++++ .../rainfall_chart_card_with_background.json | 32 +++++++++++++++++++ .../simple_rainfall_chart_card.json | 32 +++++++++++++++++++ ...e_rainfall_chart_card_with_background.json | 32 +++++++++++++++++++ 9 files changed, 253 insertions(+), 1 deletion(-) create mode 100644 application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json create mode 100644 application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/rainfall_card.json create mode 100644 application/src/main/data/json/system/widget_types/rainfall_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/rainfall_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/rainfall_chart_card_with_background.json create mode 100644 application/src/main/data/json/system/widget_types/simple_rainfall_chart_card.json create mode 100644 application/src/main/data/json/system/widget_types/simple_rainfall_chart_card_with_background.json diff --git a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json index f2db1c22a3..bf60c159af 100644 --- a/application/src/main/data/json/system/widget_bundles/outdoor_environment.json +++ b/application/src/main/data/json/system/widget_bundles/outdoor_environment.json @@ -45,6 +45,14 @@ "simple_wind_speed_chart_card", "simple_wind_speed_chart_card_with_background", "wind_speed_and_direction", - "wind_speed_and_direction_with_background" + "wind_speed_and_direction_with_background", + "rainfall_card", + "rainfall_card_with_background", + "horizontal_rainfall_card", + "horizontal_rainfall_card_with_background", + "rainfall_chart_card", + "rainfall_chart_card_with_background", + "simple_rainfall_chart_card", + "simple_rainfall_chart_card_with_background" ] } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json new file mode 100644 index 0000000000..2e619546cb --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json @@ -0,0 +1,29 @@ +{ + "fqn": "horizontal_rainfall_card", + "name": "Horizontal rainfall card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAqFBMVEUAAADf39/f39/g4ODg4ODf39/////k5OQjTMfg4OB1j9yRpePk6fjOzs7I0vGtvOry9Pvk6Pj09PT5+flYWFjIyMg+Ys7b29vV1dUwV8vCwsK2trbw8PC6x+6fseetra3n5+eDmuBohNi8vLyQkJCsvOo9PT1aeNVMbtE/Ys7W3fXW3vRohNkxV8q6urp0dHRmZmaenp6CgoJKSkovLy+su+pLS0shISHWoRcHAAAABnRSTlMAIEDfv1C6kOEmAAADUUlEQVR42u3aDW+aQBzHcWe7P3/BA+QZBETQ4aytfdr2/t/ZDgStjS7baBtqfp+m5Q5Mel8P0xg7AAAAAAAAAAAAAAAAAAAAAAAAAAAAAPhIXz69OmN4pXx2o6uvskOx6dOzlOHg2qILYF8PRnQRRgjpGYT0DUL6BiF9g5C+ORWilyF7Gh3MFguFKnfB7vBUT7f0qFBfnAjROFTVkj2TWs6D+y0mJaYgiGOFYueO5IG+kdMxRJffptFY789qWvIGITrPq4RlWB5CXPoWP26fgsVs4dw77vO94mydriH6PGR5GHNDo9p4xZJndgxZ5uGKailP9iFPzwtyH5zZQn7t1n+3+NUtxKzXWw30Wtj+ug2rk/WK591CNA7LdltDbbLfkYct/QweDyF3W6VjyPi7ZsiQls55E8i3RJSw10wnppkkciE3yU0z1eupof8pROeNSa0Vc27uby3Fuf95CAmc++e4U4g0fhGSs96s3EjqhZRUU1negHyrl8zVJhm88eQoVeWPlXk+ZM6TF1WGyjkdxESnZ91D5NCjl1RetoNQMzZy1UYayla5iVoiKzxj6XF6PkRlOpLf0juSIUcLP0j3XSpr9QMn1fAHGfVTy3xTPenz8yFpVTkOE/JS2uQy5CjsHUJOb8g6DCevQpqhwaocfa+6NFbPh5hyv2SNrssD568f+34h6tGzOw55Td1CaJwn1f2k8Y0uN1srTXo/h5Cx17w229mSuoS0wpxK7+h1b9EJVvz6hPW/Ict2TZNdh0ZvESK3wpSPKVe0N93FWBT7VLNtskeiOjEiW86zWUa27+8uyBPWv4W0G5KyWk1u1YreeUcSM5F7m6yPQoJA+K4r5CiiyI8KexqJIHBFEYvCJhKZVRQ+WaK+INziX0KWXFITMifixo+OIYc/J8chYmq5IhO7kCzw5Viey3wRuXXIyPdliDvNXEvmRhb9D/ON34+kczoyE34kpoEbWdWOiMKPptbUFfJcXGSuoCrErnYkK2bVhSCKqIOPe2PlZ3Re4Pr0N/oQYtt/umjR3+hFSB8hpG8Q0jcI6RuE9M1ocH0BH7MTWdeDoXIBH7TbynAw+Ho1Uj67q+El/VMNAAAAAAAAAAAAAAAAAAAAAAAAAAAAwAf5Damp/4Ir985nAAAAAElFTkSuQmCC", + "description": "Displays a latest rainfall telemetry data in a horizontal layout.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:weather-pouring\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal rainfall card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"mm\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json new file mode 100644 index 0000000000..c8aa515031 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "horizontal_rainfall_card_with_background", + "name": "Horizontal rainfall card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest rainfall telemetry data in a horizontal layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 5, + "sizeY": 1.5, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:weather-pouring\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal rainfall card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"mm\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/rainfall_card.json b/application/src/main/data/json/system/widget_types/rainfall_card.json new file mode 100644 index 0000000000..a231670288 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/rainfall_card.json @@ -0,0 +1,29 @@ +{ + "fqn": "rainfall_card", + "name": "Rainfall card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest rainfall telemetry data in a box layout.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall \",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:weather-pouring\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Rainfall card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"mm\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/rainfall_card_with_background.json b/application/src/main/data/json/system/widget_types/rainfall_card_with_background.json new file mode 100644 index 0000000000..1fe9cdb53e --- /dev/null +++ b/application/src/main/data/json/system/widget_types/rainfall_card_with_background.json @@ -0,0 +1,29 @@ +{ + "fqn": "rainfall_card_with_background", + "name": "Rainfall card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a latest rainfall telemetry data in a box layout with background.", + "descriptor": { + "type": "latest", + "sizeX": 3, + "sizeY": 3, + "resources": [], + "templateHtml": "\n", + "templateCss": "", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '250px',\n previewHeight: '250px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "settingsSchema": "", + "dataKeySettingsSchema": "", + "settingsDirective": "tb-value-card-widget-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall \",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"square\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"mdi:weather-pouring\",\"iconColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}]},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMwAAADMCAMAAAAI/LzAAAADAFBMVEW1vr+9xsa2wMAVGhq/ycm0vb2vubnCy8u6w8O7xMSmsLC/yMertbWyvLwXHR2osrK3wcGtuLips7Ott7fEzMwTFxgQFRWira2wurq5wsKxurvBysm8xcUTGRnFzs4aIB8SFhaqtLQXHBsZHh2strUXHx+msbEPExShrKsOERIVHBykr6++x8kcIyIZISEfKSkbJCScpqaeqamzvLweJCQjLi4aIiIdJia8xsYeJyclMDCstre4wcIiKSgoMDDByssnMzOYoqKfq6uQmpqkrq4rMjIfJiUlLCwgKysiLS0cISFPYWGSnJxHWlo2R0eZpaVDVFQiKyrH0M+lr65MYGAqODgpNTU+T1BJXF1KXl5FVVUvNzcwPj4nLi6eqKhJW1tRZmZBT08+TU1dcHA2REUuOzsVGRicqKgkKipecnKXoKAzRUQlMjIgJyegqalPY2SIk5NTZ2hIVldAU1MzQECao6M3SUktPT0rNTVLWVkMDg+OmJlqfX1ZbGs6SEhNXl5GWFhEWFhBUVGptLSKlZUwQUBxg4M1PT0yQkItOTlWa2ubpaWNlpd4jItQXl47T06Ak5JUaWtVZmZSZWSXo6Nsf39NYWM+UVI8TEtYaGg6Skp0iYhoe3pVaWiHkJBmeXlidnVhdHMrOjpabm6FlpZ7j45OXFw1QkKSnp6Ejo5RY2MxPTyWn58/SUmDlJQ7RUU6QkJyhoVCS0snNjUxOjl+kZBtgYFZb3FCVlY3QD+CjIxGWlwuNTR7jIxYbW5VY2Rld3ZTYWGToJ9wgH9icXB4iYl3goJ6g4RwfHw7TE5EVllFUVI4TEszOjqUnp5+jo51hoWAi4tnfXt9hodbZmaUoqF/iYlcampzfX1ha2tOY2dJXmI/RkZ2f4BmdHSLm5tueXpdbW56hoZrdHRncXFVa29GT06ImJhkbm5BVFdLVFSEkJCOnp17iYlpd3dQZ2tZY2NIU1JedHZVXl1ug4NjeXiLmZhud3dfaGhNWlrJ0tJOV1dRWllYYWCSmpoFBwfAn555AACB/klEQVR42ixWsYs8NRROwptJstlhZ3cDu5mEwMKxLFyadZuBGwh7d+WBMHYW1wpXHL/mqisstLsrbWysFfwLbAQVFQvBRm0EFQtFtFTZQvyi5re/2ZlM8t773vd9uWUH7TGC0SG4duql93puJHdSehspsC6sPBlpjLFkDyQzJWlssjbLaGWU1kSTje/Jytxu3dJyG2NUpLyPi2U8TsZrLRE2Z0u5GxS+k/ZyrkPFZhMrq66xuwkZg8zZW2JzZw7X45jZcYrZcKv7oSLneXg/mkPLTTL1UzSq1inNAteoO3AMEwxnpibkn3PPnbGxjJGkH8s3PiMqtjYaeoXZcazTto/CYt6PKtqTjCNWnMZoUyR+gadzxcfTze1IJywXZ2yML+xDRAQMmw99DhRT1KONluvhvn8tjYdGdqngx38ZKXYZ7ZlZS1MiLq1opJCls9heSrHSyoudwpT9N6bIMWaJN1IaZkZujfbGy9AFQu0RH8lbPwLN5OopJ0FxZN1ZxHVcVT5SgflStwOQaMdTuc7366j6EGMBOpNTIfGNVV7SeJ0i8pZhuyHaISVQRB3xOO5HeVZJ/V9WE60xPi98KUsGlolbzMSnKyNjteel3p+eZ1G2UJKx3OcCzRYcTxM5lZX1DJVHHbm2IIgKXEQG426/CmTPaG+SlvZ+Y2lp7XKstRlHC0bMS9XIzcmeIkmws1UeEFMsZU3W+/EEYDPU33E+G+1mUaABnOVpqe0p2dEgCvi0ZMbSfqp17CAAvW5i0ChAmRyTtOzarA4cBdSpgHlnPEhlClrP0SibrUxy2FXKG+5XiklZBS9lN2EEwFTQcI4JU65+kWzcLaRoI0hoow0SfGx+fexjKQ+0nE42Xl0iD3Bk39uxGI1GVLheIbYd5XFp2X2CKqGUlFiPqijmEW0N0bh4LiODR2s1Tm1FBnZqKuiKSz8bZLy3mg6luTbrndX1tYHgnDJQEqqj+wXxIbjbAzQ1UwMDggqln+0OdC09vFrqKQM6hZcoeg+UpeMuxPPHFg1+Mlc89gRYBVr8da1fIcBBI7QtEzygaVgn7TkADwvqi8b6OIqLpjIqujg5p/HsNWMtZ9Na9pAct1BmUVh8gwcmW5Byzm3e7arAMSsR3sy/YlQMdOz9B29/vKsqs54dtPWKNA+ecQSTlivpz+5M6Kg4rUbDMVAUoInosKDYrmRiYclGgIn3Ik63IwaKn++svVGR8E9drBbdKiLGsZgZ0Rbn8DZ3YMFEJZnmz++ta/7iSCL6fKW8Z0slp11pHbALdBs4MIyU60akXIQkdYnEOd2mKhCXGPaTlr+vuVbcSJDh562Byyt2CDW/QADrVzZAcEorK3l0gLNAAaq0uEGiKuKyu0b7Yrx9/z+V0W4Xx93p9D6TxflSVC+tQl0sWRpdpiosD/6d337beRvh3ONl+IrGoz3NVS8WNZU+ZVDuWxRN6LuV7TvXEsMZm3NKg0dpD+dRQVhf3u8lZMLJy9+tHQez4GtuNG+rjup75x2TNHgqCjReHXwQxjsKUjI6QScuV95MYReviopQn+JQjC1S9HjaTGLUj3d30paejgUhoepyhIA0rN5uDLa9SXQHTXkRruQoWXwUDjnVMWh/+LIbbHt3g2VKyoeFNVeBMCRja/hWkIT2z07WeQkMHFyXc5d/8M6uC2SmZtcGQ2vD10xww8K6oJW08U4zXrlCqDeOm3LuiScFkAal4kEWL2UeJQCMEA/DI6qOuJ/GctU22AgU4M5s4u3VsXeRCrM3etiXtcLor27ujR4ejC8ijyT3Yy1yHdfrydddq14S0uz3EDbJtdQQtrFPUio3WiNJw72tAVAOdqSpuA6Kz7unesk8U2QYZ+0jeJtwH6BAQgoOlozhkGLrrSaLwSyfHJzsewtE8U7Grbi1cgSWIIu35fgG4yNw2WIsaq/20Z03qxM2RmTFkhe3ox6sRHys0q+sqG9hIXCFv1BzJFhpe0djsI+6ldUQPS215F6++FLck/PlKEooT3OmA2k8GgnzNFrwqnXi78UinJFHTOZJm2b+Jp8YgCcYCnDKQObOCA/FEfwYFzYkC2gZBeZ0Om9JUpx95aIthkIL4a/3Jdllyy/qpZcgZ3UrC7ubytvF4HUJAwsSqrxs8dgaZbQKBmVAovadw8bJthMydA5LHu7R4xfTQM2tAilc3r2BumrDQ+HG+DVoMJwDYrU8VoaMaYDVYcLUex0OmxdCXdClV05xXvTJkcXYsfSwRj+Sy0QJWnvrcGFidK0dzqdRmrEumlyOz8NL+bh48h6cyTj6po+vqcu4hTBlHbO0U8iqg7JT6LWXzKL/xqMgKYvLJ1pCKuQ9cs/4ZO9bTrwjs8F7zC3U9rl9fg3CIQPHMbO8gQECM4qvNDeX7i0G4jgBrbppTbUgU0klBeKJoFk1Lc/nVdxa13QlH4jJlO0bm2wj3W4l49IW09cC7+hhMuHqeo104GO8pGSiM3tp51srtkQyW4QQsF6W3k/XW4rKTFov/8MCizS6R9l4LK5Hl5WCuMkXe6H14XkRdrNgzPxmzfmL6XExCK71/qGaGsOYGnhgf8JH7l7vHhNsYxRjxMhwD3xThhyUvFnzYjhmfR/Om57ygMbb58WNRHVQFlxObTMAJTxeSCKLQf//Erz49qal4hWbyJezJcp+ZeQmhQJjMUcMA34sAAIFPI7sULiEoBDMYwrDaGhMt4TGcxIVMyZwXoXQNkrXdbsWrOrDZM/21TEYDvLrJ8WENtwI1yoAI8RCupTJz/RMI2Rab7vXUuCZ7FvLm9MDvR/cfz+JDz+6xmqrg+lSgRQNrz996QA48ktjD8ntuSUsPK9kvFZmCuAIImtJaAjBYQACNOVjAKmUD1Srd17muOsxzcNAZYovO6YhfsGebjgPgd2c6c1Za0RgbtJAaK9dQVW8MgIdCoqDSAeXlTDE5hRKPkvghksvplXWumrylOoH5Sedq9H8g3svyFIsVmKd8JV1/Epuhqq18v60nPYTTtnk/OmvOy83Wuacw/NXfXaE4MbLU0RKTy1JkE/kjZJAc3MlBe6RGtdgIJU1ytcBG2r95fNkw8W03kxVdWC6Uz1zc+bMWkN6fOuE4ooL4mUv9OCE7pXETh9lO3NN9aYDVS0pabHGounWQyMR+luaGO9lm9NKrh9vIc0++/Xj1AKBtxOR83o4X8T07gWxncxdkweRv4zX98dEcol00NR9b45XG8I9km8m5Qxd3ew6IkMECN4w1arD2UFx7dSwDU9/173mdYuSK3Zog3hZTRNjohxwzz/slJpP7ngrDtemN8NxY0gbtMV6FO2Bb7FlEpnCm2/OyjlQXCrtf79aXkmn55NNGc7fyZXthegXILVKOWNLsiLS833Od27Uypusbd+I/Zd5sZL03uTgS/i+oTupCSYRX319RJdAmkkZ6BJRgo6UrvqPOqFVj3oDZDc4JVwQQbXXXFR1xdeB1a5lbjd54y+tNWthHuWo54GZ6rvXf+ZUwhqI1m2khAXXb+qn2ypB8xp+ZkcnXzqTka1Ptzh5xfLdNV+dD5G1y3nM4+yllLhNmoacN1ul0tfPfyOYzBgaGniL5+5lApMwzMDpesVKg+a9tycowkDqWauCJSXVh0G5QByodlyHFoDYIjhnHFdQlmLtUGlWLKDq5/htKIJUQOPZH0/c8M/fmH6hjDHvXnj9mpAh0FK59kJUlEPI9vYDfvvm5Xt5sQQ9k/EtpJSrU9c01gqXh2Hx+KJiwS7emWQSaPFciSHJ/kIG0Nq4PJ2raU4vLaPS/jB4InwoQA+O2XM4xRhOmqqL7170DCpL2kH1mOJYw9Q9Sq2ZPhx0PdH6WHUTx/Y75oBq0V68dwUwHKQJAO3Z+048e/89wsmz7aCSgZ+8+GBJvL3O1h6P1Gzp5TDeWWuNlv1IQYOQS7H9KNC0ARvi4Rr8yT3VGfwk3UiWuLxIWaPsGaVh4IYyPZ5O3kxCAXPNvWkxaQ7IhkRm5rr0XTufYj9H91/98DdzdxvKIRZWnHGneKvWLWNqpd7RQS8WTIdfv3/9d1AyrFT9lVgoKufZOTOzT79dMeNq7XNmDCzTTfO9JGops+sXmZLMj8fa2twnaU8Wj7BQEinkpB8/eG9r8Yqrab8Oq55STpnjwikYbFWc9UYJItNX0dGqUEHMV3yDKVPEnlByz9P68uqmQkWpq4+/islqPm8H9jxwjMltp9o2OK6N0reHoTmD1lTD229uwr5hlz/88hXeK4MVGEZzJBTUh9QTpeb6+vFL8g/v3jXbqct5yKK5SK7LAOG9LucPfKTAQ+4bhbMvvzuhqylIUoPLf+T9jEgmrQjQUqCrx6MvRyVJ1D+fcNcH0/ZFXbwzptEoIH12AfpESuV+eO07aw668DLTfNY17Exrpd8/rJ47VdedWNeO3YXNOy++m/LLRfdeu31bsUatFe/dThBRY3jI7Lc5TzhtU6e08sOEVeSlledKXm6lG1CY516uW7P8cWEZ69751S5Wp9Ym+Evark/Z76tM50PDHAmASZSqL19SzBlgIe7BjzOzgYrlkyhtDKHdwb7nDTzQQ/hpUO82i6/3ZtKKNujrX1uuqxZyeku5m0fnAhumX7aCQXVu7YIKulnah69DpUTL0ZrFg9yzFuKiYX3DeS9dYoPW5Z0UZnI876mbqWFuU4WG994Iv2ZDT+ppe/Gcp28Jr9G5nFc5tz//w5G5g0ZQhHH8m4+dcWZnh53dFXZnMggHx3Fw29xtM7AL4R5lIKCdRRqLQIoQhFRnZ7BJtBALsUgpiaSykjSKbyx84LvwLSr4KFUsxO8cLm8y+/2/7///zWZz9i51Y0hYQmOkyexPEnd7NNuBak+//vWfhtE8Khy/4VXP3vnuqzXFF6w2qSdDKdVaKrbM5GAVs8J3w3VbhjoTKoRpEqSUUDl+12AOkhYAOLr03f1lsIS6ri2PQYOYkNMybfYlGS2JqWyjYsD09p09LYoxbRObi1+L96/W6oGMPVgf7Ds5RFXHh6j1eo/eJZPkASr9kpIw30+ipchUSSRj7ZMKOpda+mT6Fj4Y6Zvatj9U5smhvUV6dnqWE3MJBsh2XedQBzkMgwyAxaQPR6d8NLJSuhNQ3jkHKKDhXMAlokOE4JSTUtF8WIjQTwCDbh75unC63H+SVPiAcX7QExvaeq79pXa1QMgfGJvz7FLa4oHk+EbE7R9PPMfm82Fond1niLi/iPuJut3MJWGYtZMbnuz+5nZJS4up2A437YM9b3PN9NWmpUeE6p2TtYdKBurktpDs0jnmRzYM5dsn0koLHy0BXFDOvn/oTMZzr6S0t6vCWQ/9Fu3o+0tJP+e9ZZK86B4ppduBr05uh5YCTfUohTARx62+00kKjvztwgO6/KduFvTAzBJuZ+lD0IP9KOxRBJZFbOl2tFGtplNdIjkKhmTvgEPC6DmM1oS2YXRTJMPhQ//Mkn2kDc8n/3Qy0URlF8h2icggtm3ZHhtryWzrWpBpWHMxclY6NdiuCsHLg15WfvjUzGBTQM+dLcVFN7Jz4lww9HZ9+yi504OD1SgQTWLL9KBs29Ng2iSIy8Ed6dleZ0CgQlO3fXvyzlmL++7ooX8ayHXQ0yeJwD5ZAInZlwktaorW2VhrMm/QZZxxXCcpoXLwLf0Q5kydI0WZkUOcZiR3pMdWKRZ4cIIzJw0FfjIEFWiRGoUwE/M6a3CwMMCq47Bbzm7M+jOwqop8JdHN+zOmGPAgWadbampDBuZtgv8fXvrojOVXQJwTBH0/h0FiPH5w+WSyr+DsaqH0HpDdnzxOonmAkcvmLd3L7Zfru9nuaNTk5ai098gwNzT23YnKXHJpODdqoG1DWVaM0OPYCCgnbVB0JYojkDJiikMWsoMo3bzJ8mnHuYejt0cmP+UcyoNb23A52ZyD+/Oe7LdxqgnUosB2s9bgGIHzRINygMu7q50PSKAwhu7aXKNWhq23LVwuyDKLHfzo8FxstD6uyVsyS5J3fyYbyQewbaYXVu+lB0y1mU4yoGkRpukrkvMgM3Q11wSZHDk+qyWjwgfZ8TB5XUr4LJVqCjbP5sP1Vg7y8EmPooSGppiJdPP16zfih+0MoMh/t5h5+dzvC8zGTXSgrGospooxrrhUUVKSwFoLnJPvYGbY+32gho1DXFamLursrErl/Dgeqjaukv02+/7tqAlQ9CnfXyYPnbJICIPTHo1WVw9MojaOGbXhEqLcjyiZbHcMppecLT0yyd9+F1zfyHfWVDEZbFO7q6NTwbonbV131olyJLsMIHsEYfjm+CS54x8fkM/Q26YDsM1zFYJ11kp6SQ81XYyzQBcg+7o2YW2JputQRW0npQ1rTjVwm0gL+TnNqhbkwzhq6SHBxb6opW6gbbHkap2iVglRObLkIa3SiQLH1J5kGuc2nmSRhIBkkU10kFwNhYzq6DKtQ+3Z+RLQBdcNUk5PxkqEwWb96NTJ07RugN++m8uuafi7Byl0AhBS7q3orD10OJlSktSYq+PgKGEgJU+R5To3MiludJTpR+8kCmdH1MmV30rWxtndRCYhxLChahND+SIx6fKSsbu33/2IUpMX+7t/vO363mpfMh33EpKhdxE/XCBAWJyGpA1RP+ncbNwH1XDq5/VJkJSPHieDdW5+74SyXBlRcPFpX0l7dohFI79/oMJRhR2QIgBeQGM6TK+eRNrhz7OP7EUqucuZTCfEtieDY4wtsxRIj2RskX1MJ54UJgD2m5xmGPdMCzpJpttbgcttG3e3Zg9E2E7WdL/mkv0HXLJHSXmukBbh/qhoGIs6YmyUZgR/2TuLutUEMQigCAHqWA0gK0taFHL4bbBV+ubigvuC5KxAgSkk75bCWkD/vqjAFp3gvDn56M6BsGVRbormyYtycblGKMCiLKzcoAKllvcuOSwEV5m1qq8zD0GR9abpwAURJewlYfuuTODkn4Vmh5uWzvJ9Wkk2q+7maaIIx0wlxe0Tj1100EovXYiyjDIiY7vipbO7qNMXVL/DzeztbFDK8deXUkqXrwxan65TTVzjExi7NcHLUBb4LsNu4BzuKg7TruzyQ4HQlQuBxuPhp1NDe+9iM5RII1Y0aL7+4D5IDfk7n1+PJ7NbpwmrHvzAXWm1YjbQ6TDJ2sA2RlcfXyT/r0gnJtlNxd3Dbu2IiO8a8dSZJF4h6PajBWqb2ErmAR0amr185ItPpV4g7z+GNcSZrT+dSXfQ1305zhYze7UmsxnH/XDEcfDoM+fQlTk2iFcwWpx+8m3FR4WHzen13FyUaQcAeFh4T34riiDuJzIotlze7QaUVtk2BHJG0IGbJo/WamA1zYiCC1Y2JbMqFaVesB1w293SRaR0ML1bZ0PQhoFmJe2wNHL895vzJnRKB9hBWL66ejsrCYzqYDoBqyQNDLkw1lvHCxz1IIJ7HQ00w8BtvhwGAGvRYuczXnTlt2bg41lagx9x082wybtlZv7HmYKyFvfPPasacFKrgBz9+Qkq/b8blJkq651ERUWcbsM8mqQYpdeOitoV75SKSRujghxJvAuaAXuHHnyOdMWZ3mNTmsTZQ3otQ7RK39Kew+yCxTV5YdkWRKUhI5wGHAZnuTShmpXoJNnK2PffhgGHwxwRncMOoAOBdT9fXR9ledetYMr9QWNGTQXosfhs/jph8PjaH80vqLwnzwOb3vYK0DqUO8AEI52xkRCjZ97VJ4DzIGF8fhKI4WdL3ciEVMc2Bp0QflmyMOm5XuT/nGeR0bLpcxhCtj63rBcMVVdJqeT1JVIAqVXy7qDi1Vhlaz1FnzYOV6SMu85/Rtq2/QLzKdqbGYWmE96DH5fgc05CqnSygS4VYlKdnxoLHMuDM7Q2/eIHB0jTHpA6vH3yl0hCikA+m19WaHrVZCRKLaxknCqEMYOyJMvpm2uJinzoqPlBo2OJji4gMobvO5Dq2LKByfe5IoiApKUuZvKAkDKwUgcQaiPODcESKjuR4NKuQXD4yPsFp2jkgAI5IOB4M0ILIyCVX91ORdlllfGNqOfQLBsSRnbEApBn9wtrr/FbsDAIWYEZ27S+hNpjUBSh0xtVZ0O2POERnJJRshj1yVK2Fi8ltT06Js/fXeBGWpnEwGSMVqKJElkf/1el2FqOAm1mQ3BW3vTlv8YOMqChudCOgNZKN1jboEPbDELAylXWH9aAaA0At5QS5Jw7xXR/MzH9zV1fjjj41MNotjVjCnUDaWHg6w+fARy9c40AZDcnpMLIkCbsiwylKkCtP47DQEXKaOm1nEen3I9vb4Ezdn1xT+W/PfkLodWGamOtjhF1S7GQVikyErogeq2kDYQX7txN6z13Jg+qufZqeK4uvEMD9n9fr7eDKbxYAhrOaRRpZ/u8mopm7hteQdDVzDZp+uZFfr0GSMtTSD/Lb/Ou6SoPvBxf731hPABmT36KHKQ1yoxxhmAkOmeGmqvy3CkPY0s5P7pjE/+c02x+OXfLJtYnh0tmPqrug319qlyMLWMmE4Ym5Ha8uHKjX37l1H423xCVbmqpBm4MYINMHaixVJXHxtn8k28vKBNfvPF7iryxhsJPHzkXhdmgeLvYvg+b+XgDWdXUaV++fV7flUTkRQHrV16uzDuP/7jKZytei4t+1xgSUkh8sjt51QXrlAWBciNxtYDxFlmjCtKpWGbI/DPKaICoZpWMYrxiRZJGpVCxwfRVoMkwXSgG/KAXEE4eSCq52Mp1bsGt0Hgjr24/cgMaF2oRUODVF2NnL6ZHbpm/vSemHQK6mn//UQ8GFgsPH+VTni2q4hFAIWhuec9Tb2aTab/IBLxbP2/ESf3SL6YZewOjKYATpwglzxWWvRwmhVJKuJgTBCaiBtnB7YdfEkhjJOtL4hpI1wiFy6lSzqodwEcU6WA7GykIDN/+7vdYHFOLwWY1lqfKZaP7izArvTwa1duCwkPIKqyy5fYjf5dzpH264ZH7O8jcAlf1Zn2ejnpzvuDmJiu6j6+amajGE+CF6dORb7rU+CItX4fugR+a7ECvPhEcALrJASz+4oJ7QIu4qaphsBSffCMVmtB//6ZyXB0sDhTIsMssklBwKko+bqJCXjbHp0eve8WuWXpoh1Pe+6MSreXSwOHEOYV9P3rfXS1Gl4X96YX3XjOWlCiiifOjhs8+u9sQXTvEriDmZjfYN93dbKDA+8tL2m3pJ/wKRbf2vOBnHhrPr2ddt6lvTvsVNLezmTfXZ0Azzzw3WZfPxrOiFOnXn8+4mK02Yzvg5Oqzr9+xTj58rewgOsN31y+ikqz+8sUciUPTQ34inouVDJVqEP0gCSQX0bpwfPVwMvK2G7lxDYIbqsKdLs8DfvxBbk6PqsYotOn11FvS/HpEkBaqshqtc+z5dNyXJ5xgS8TNVgVNYNJUhmPaeS7S2ToX/Lmu+eJ7Pln4BRCmRNM13vdH7ywNcA4Iqz9+bTiG1x+dwt3Xr3I7N4CXBycHX/ZdQdx0+WAHp+BQQSavIfuewm7ETK4XnCSCi+yyTt9PZ4cHE+UoXGImdtqH+aQRXvFOyAwPjbA/gkrEdea8Azssicdg0XWIYG03E6NRht5ygJO6ovTPpiCavus6sg1kp2eGT043k09Xwpuj/n6UielsBE3V7FbmF+unv+ekBoG7uOxMV+7N3+nfh29x8XGgmowoqwtEHJQpTIErkiMJv9MiuVFSTnzmQIh6whswFxdfxpVUVg27QKFH6ej3mqXawoCnBbW5qL0w6ZfzcdtYS37PJHAkMVSAv6sR8vspvp5evl9zqp77bc4nwnNe9uumO6q59ySwySD/lWw8OvQHt9X7Hy/6/zi2lhAHajAcB/KzxoQ0iZB09DIQhsHxMjMIwojYmR4LPVTwVlAPxSKlikWkKsKICK0PtKKi1rdupQpeFBbE9+O0uq6u68G3qPhCEXxcxL8uSwkdKP+f7/8eSSlRABBq7gRkXSGwGVIGmkFYFF6cYQ09e9lSLCiNb7VVJ8HTASU0XhCxCgxrY8FBt+uuvZyRdnQhCgUNvv4m2puyNcXoFKgwPxPv6LBKt/fO1AatCvYCChHGXx5rQOoslEhpgZwixMh5BAF2rg01LkulUcWAJFTTUHx7ypE1opTlx2ozj01EERA128IUTMXTlJW8u1xlZP7RAvjy9y9B4IBRQbEzTUU9oQ52c4pUcojvu5C6iPAlaWfd9h5pXHs+68yJSnAiyMbGp1iwEIEKRMfMLhJAov7xX6hKwSKhUFKw6a0dFHKMuQF+Y1WqVR20QVJRiF1GuYhQQOoU79R7pmaIBpFOjUjNqeu+My9Cf3Su9NjNzgvFsGO9nGi5+OayB2cdcZIqVaX847XSQ7L54iPHehd9yne5ze26ESGAdz4oYkMrimawNzptX3TRXz8QUZKLFDdeV6uT/WcIBKQEmHO3OeezBoMAwdnnPGmjDE5XZy4Pz9wL9WefWQw0QQ9o+AYs5y16ONjdjnQpyyTxSrCiRGCgIEXRokPruor4gByjrlmgfUnXsoYBJZqqkNT98HC5UpWwUeqE+LTcO/SDoQN9BGGcFuk+0TVWx8VQlQlYBSMoy33CXOi9nZ9Otv+jazPTIdN10JruDcNUkdwGyWGPTFXMnYttwk4c2uRejIM4SdMAuxFAZwm5qN3dfBO59ro9k3hsENkkOPnzHRt0uAjWt/aG7916URAgSUM0msDM6NhTTRHiggNXtsIlSm8ROldwo8LSSlfWaWms82UI7r3ONHUhi70kfJx0WW9IvPITBtzkUJouGC8EqDCUk89ClY83g65UnorY+RRNBGmT0haehOwCyMdB0xC8TTzoUBe2qRChDs8sdmcggQwmezknSAS8buuYFkbw9n6DiZ2sBz2UKx22gLXsoUXax52ROAiweocE1/RwaMqRbLRJY8LJT2HOJ/Z/tU2FaKTgUJ+6AvtJrexwANhXUjqmPt2YdxnBN1LIIqG4UtOsDg0zDuifWTLeGRVX3qHv6gilP8YrNYFCQ1q5So1QRpzFxwctzABy3CYNBEqc2fcFFV6hhIlPvzxu7cHOL/leiuobhCG2KDhtpwrBI6xIWhkIYkaktTsQkbDlTKGU5YbnIMJGh33KhHJodXSAmRiUqytTvkOqDhI7D0tnjAfHBn+6Q7mJo5km2r7zD2PCKROh4LlKMu5CUdFbe5IJrupJ55QaagLihu3AfXR5SXGP9g04GgaUkJQE9V4VQHsvbgUjlKk2ig9xWPe74y3qGa9C3+odrynrOwzxLC3PzEm65iRwinMrsENDgB1M9lD/KBQFQBS7gggnFM7bcg4hk998DmHfGSd+oSVUhwogxWJhlTunwDupZddHxzNLem4x6UQfO1NW2+owAzXfEWjN09r4AciYfv3nX2R+QIJImJYZpnUYxCRHDUWtwfDexgqBYluBji9yKghHDmesyazenOkT6oi6KCALTO8FSUIX9F2g0iSDRn592ggVpcXJNgjLYJLRBChd/nOtpkj3WDQhwz4Fsrko7LFDB57YfZG1JQDM1SoHk2pewsjnGpK1v1Wm064hKtJRz1ljGst8EtrEg9GycJQP0qGpu3S87V5kwjAc2QGI6QLRwPsRt5nF6cERGh3Xe4TsXNv7oOEpzQVsvnaISV+wMW4/4qfoSLP2lO1oHmDmE2VgWuseHbZGUviGU/wAlGNKk2s/Tg9CWmitlGiMpkVYKCf1gQCnueoilwX/OrWIR8lVDM23ByVz5j0mJ7nwjJPa+4UHrkxpIpZz4Z0fgeaFCGGQCDVeLHRg2gEvkb4CfQ+1usEAbJHe60OpGk0VijGInXvzkoomMHo4aIs9WiFevNXaXX3lOMGZae083qgWOEIoBrGSUMFDTnepA49BXJr3zjKHhgoiqMAX5xAcOmE9Bi5LFoUpFZhQlxUXJjHelhs7VIaratBxtfXvfUlm76bww+8GygX3PImnLnSgwe/7YeJNT9YkF+GUizEB1QSyGQsrgioWgYbRhGF4Cshnn79Hob0D5wRBSHlFAsKNCCKvAvnRO620v+xEk852zLAbxFJXAZZPA5TlUImYAd0qElbS+SI/2WKuIezLoSD2r/dw0nzXQCfsYq0Ih3rHVAvAw8sKYKVO+mndKaH03hglIz4D0peytF8C/HbJp8brwXyziKLjvwA0TL897U+KqnBYccD6G9xySwTsiYuUFMFhSjPaGuU0ZMlhoByIltK2ajnUX6yTbbO3firQLHvC9gOedwj6wUUodegdISAwwc5hKhp9fsypJ7QAJorWMOaG2OQzXYuQ9IaygGEchrH8qfLKQFdbXg8WaPlx/2vjt8dDNUIyeQ9Hmvd60pM05RE+Vu/UnzZ1lpikq8JOJ3IVxPFnzBEyYHxMnaKch8t1MVn1u23qBNimkamR1rVzS6IUJR07DXa1KmIJ1Um+txVke9hmnpWj1E/+qWWZFQkBTohRggZyeIz8GJqQdh1F0ZD/9kgh0UvI8WGHo9lR50B557I7Vx4UdAAiBsB8qMCMvHr+07d6Zfn3keewb354/YevPVElRGiqs83iXV1K/Y0yspOkJnZyMlZuCKPP3iPCUDULcDup0+40FEoEwc5ooOk3ODE90ztRBFmMiFAcwo4eH0R9dTbmFnyM7bUc9e/Zvw/n9O/Lf2xx7BeHUrmf8lAl3Huih58lVFI1KJwRceoLyI0xA2vc0YlSsNwrjDOeM+m8Ando6oGUanaCehr7W5mRfGZvzRPFCDO2hHrZZX3NsbxQx07H0lTO5HMcaQbJfqUKxR0dW3fyUXSyeZfsCg9jYUIkvF0It+pGLUsI8tuO7jklpuyWSAWCfdm6DaJdOm7eyf6NV/QvcqBss4t827BMF//89q8DLUx3zI2m3mN0CX8uNwKccWqeRX+988saYqadch4G32YaFOz3TKUkn/S6w2OuN93UJHo79D7WR+S7iz/lab98o28bVSreN8V7iQx1VkWzhm21w+OiF9Io2qrfdbf+G/fYvuDGWqgyiDDyiEzQdBW4xcEB5ZU5EaeqxG3PYNcx360tV20h2rMjbsXReNwCIoG2+qEwz9/12O0HLnKQFyCoYlZyJSIRhJHj05x5OKmzAEArydS+WiYDhAmc8mwUOc1NZ8QU6yb6nY9lIjMpNYGjZyHK9ks+7milEc7uNlMpeADlrR4g7eLJxiBFHefCUCQRCDRokcII6tKQpoyhh5RZ7UekCDgGUkE1xC4UFyHV0zhGA+FCWJucnwqM2U3oRNIdCmrj7FXr0yMqXfZehxvDv/nMN1q4eWUKUBYk77r/Lf74ied+ygxnidIDlUgZx4rr/CRnNcex4r7SVWVtN0tI9u5IzxZ/aG9S0/3oIxUp5F48veEjx53xuFGFmO0rEiNHUYogOrJA55mx/T81EF1POZSrnSDEQF2ALftAGNY66IHiDDhxQojpKCEVBYqPsb/pe+u+p5Qo1jvB7wKPCaez7r91UdAZONtf6TQOS6UiXgDnh2Ngsx+Cc13E0Qbfeb02VivHD5MBD6J8zHSHsXRQffz9Fz9nA0le+GJU+eOkwt1nM/bLe8p7Bupd/8m+cZEB8dPprVsVf3TFkSscpfSjX26WQqtch2WY3ZpCg2orEHkQiBfZuR03x8di++/goz80rcQ7G1fUa9lhPBCIRihEHdeAS4Ee/NfJWTCR6GyeMhAUDCilSmC5U6bLcw6j307hm2y27gxYhq74mf1Ycov2bpj2EQLDzZad9AarF+5+6Y79uSQPv/TFNluwo7//khHMO6PIaA+T4a3v2uGd32iA8WzxNfz99mMXUKw66t56xqkECgpKFLyVWeUImKEkSL2bTimiEjZBjU7j6qI1py7J5s6AtTEq7fwtlBARitY8CMeSvmEdDDeT9RJq/a4VjsLO/3pZGZ52pm/0OUQm6dz6b7LOmE0G3jJ59G7dNaZsmrKM2CT65tutHv3266Fm2d0vffjoQ2/OyJO3ffDLtJ+tJ1PujTTcODCh4W6fn4i/c/WxkIdh8/Xe3u8XUS29d8tYTmdOmA40qm+IoirovmuMTC9anxjBlzsAFAEqbIe6uOhFuBTzCF++Vu/YSFBCYqqwtxCI465Ybz0pEqsmAHzza+J8Y2KbJoqPjnXEnYkmJz+k1vb70YxJNmCLvPE870ofTYdjrX8ZDHW+evqfq2668tFXyI93vP7Med+vplEUwWi/8liXnn7pjYbFbGmRP7kK4WD67vEqcZy/+8lfzaozUiLmWX+ZJX2VjljeUU4LK2OjQBCRatz+HTsKRwpKCwJzvkTqbDvJ1GJTnAff1IKJcH+uwctOOBAs5lEZ/XDnF7/Y1Ji8yzXzHhvpfPtNonvDeJLnHZ+YatCLkVNNvIqr4TbimiXcdO1PP3/0/vtXPfLobeTep288463b3qiHOpLG6J0g+gPcE+9xbuFncytvwkbH1e7UVqXTBBUMYGRzu6n+Hx4aV8IhFnSfhgAr+/WBMD+NtT/tCQoMYXEOUhser6US8BMTMWOC/Hurayg+Zr7POVtFyKqyEj+QvWGqo0N5wkaYS3TV/a0XJPk3095slme+ruMkllL23pBxqhn+jZLlaP5x/+dXfo5fufLJm54k17z51OS277/IE/vD3MzjbBvLZJn3bvhjZuJ+1Y2VreaKubCENxrbGLA6vFXbHkgz0np5aMSuWjplq5Xo97SCzVRX2TfJXKxBxN98a/K8weSuIkCxns+XuRKGz+ENxTr1q4u+KqRJvTiaJysrjzq1slkl8r+uvv5bYyqffgabfNibaenjKJIRdtCReoDbHrOIbSepHsTJ4uO7X3z4w4f/eu2qZ8nLLz1639NPffBxf/SFPK4+ve5iNFPtv/3ilj/4zAB0t2EK+rNYxVZVu38uTWxCfnKrDMvPLn3GIyyUyD5D0FepeWe16qfpUfll95Pq5+bVp+77ehQqnX5+qqqocLObb3kAQFHCDeS9Jf7qMYbJG92KIVWVgT4ty6Qx6fz+t1ef8K73USeLDOcDnkRaSzv+8a9cJmw4PrGMfflplvWiyE/2X7jiq6sev/KRmx7/m7z84cM33vH0Cz///EWfN34Zf/Ked04dFO2PIrPJYunqGlUfItPYEWeNKUUsEuO0BRcdtb4EnziFGgU07YPo1V/iMoSZjGseNp9daNeJMv74PwqtNaaRKgoTo1WvV6+9/XHxmUwyTibODzNjNNEmxk6baEJxNhkfi9G6Ws2k1XS7rl01bVWkNkqLILQqUmgrdS2IKCqINWgtT+OGdxF+sOUVUWENKlaNj3jsH0JaJvec873OLaaFC5qwUvu3VrsgwCDN+FJ2peOCgGx2+EQ+ZtPNnIXvi1isxCwhgWz7Lzp/lqowCKyKbAtxnCE4NIT+SWB+yYk4OUGRr3qRQ0RCzGkvr81M/NbR7XZvnq75ZeTwt8N33qnm8kzC5h7vdgz2hlpuZSrmkpqAIFi0WwQpT/JNmC44BFizwBRlajVfqQWDPpcZorthMkuq1dxUshJ7wAKmq61Q3qwq2FyAX22r6AJ7oJaaGb9zBY5ceakJU3nLpolk2hcg4PgWyjizORZhZou5LHAEsfWlhRhZlSQiy0IclOmPP3awzMhWxM8hgBrVnUGFx7M7Ec7FONcWnUv2Pt/cnQoDzLof9bTM7w5WVMJhUC8zfyXVdexDGuXMRIkITDY3GfKVDjNWmEmAD5Cmpe9LTc6EwCwKT7jYpWatSZIsTQkC3+I11VovNRHRQq5MMIlTOZElILJDkkA8lvpssDyqUq2MkRUpIqQyKkCQBFESDR7hprzkkwVAMtGxmTh8RObB4WXBHhSJQHVZ0EVRQQ6MDn6qpcQ3gHTCcYg5d1s8dXVHXzha05lebn9l6DD5zn5pKQ7DwYLPMsD5XD5dEtBAgiRMq2jaduV0D8tjxImFVRNnXLrApsyChIHVoMbgoIphkkXb1JIJRRQMUiOpzjj+fcVkSahywmyFXAPg4mULZ5Ek0QEtCuzYzGYeYiznQ66ZoE4SMlItvEogyFPJhQSuJPPUrmAH1X06cRCEUJ5jOtEJmnHhaYcLBqhzDi+vuFifv22yWPfNcn/N3Z9u/ds+NBQ9rExV319TDBkSAIrFegJifC0hcAzRoC2A4Olm+FYXBwsZOzWrTicEQ6ASBWQARMilpqYELV0wdalFalI4bW/bK0lLk2dBGQUCd49OKNkMyszDLl57aa1TsWxLUzqJ8DwstKR2egmgJqg8oSwQ43SRd83CD153irK/TyRTX8WJymuUuPac8SDhiF3A2MshhxcUHXMoZqtobRnPzt79NfVHmxcPh5KhyfGqvzBWUvahR7B5IqW8PfchsVqxlXLS/7mbNjnZNP9vn8RzJisF9bEIPNzXFLzIZTZ7IwwLriZshhuGhNPhVK7ELn8MnhMfIKrZvDpjqq2lPO9L5BFv5y6t9VOfaa3/V7g34jnfgJfwIl6wU0b2JC5YBhASQmGRRZzD4NiBoA0kZIMhzkhIgKwyQ0i380Q0FMA4RNOSIVcmM+4X6mo+b2j+IlRMHhbbqnNdh++0VRIADSzmtfKWbUmRkWC1Ap50E7JC3LZhTiEMyTaLGYopme0Kb8Hx9W0LtpkJtublvY1aTEoax++t1xKOHwhAWnfW0p92boSID39CgDlmDArIkGX16hUBWcCbIXXwBBrd45JFhUl2RCj//abIRTAFd0H+gsz1MUTg9H4mUiIITJHWRYSIDwUIK5+bqlb3xnqz7d01DZ8fO/7LT6HQ+O7uWDIZPWyBeqplljg31pbbNwwBEQyhrW+jj1gQ1gwnNkvQIyCtBRZxYeZ3yByCTGDLFQuXGljJA5VcjGA/A2Bt+Vd50/9vuf69UTcRWUWyaApYCK+DgxEAiYh0SgiuZRiCdcyWFxmkQ0USbX3eSzUmiDQPI4KzG4aCcJ/rkxuWHYgJSPtohlCk7ATBOPN735+LTg6Fip5wXU1ra0P2T3c4PTY8OA8TWhw5bBnPVSq/7w62HI7l9qtVeChvtfUxnFeNJsue0qRTC88DWUVqYfEZALcPS4rVakFxu33PgrmESHm43AO7kyHxsr51O3JSGYHvYUwRF7E4RAYl1OomUDg4K9KZDsboXPH9yyEcWUecX/AGbURkkm8FIVUmMK9praytvfztP0s+TUJOJyDGJkIjRF3OTY1nvwgXQ729x2sa77z+ruO/fPFpdn6+K7kYHkl1tGfemavs7w4PjXRNtrTMvFqVGZVAtVWvJGgEKKMgg2KBwrpENEiI2KSVCAVM+4lkmInGoCDV9vPPftgmdIxdJhlSCFX07T+dFkR4xTsNIcPPW2QLjwm0RZSR7sJ9v3MBHBTt6y5IgAzARKl3y8s5kGOW6UhR0L++pT7Thk8hPqI7lYSyDk71+ytT5YR/bCTsCXcf83TX/LC9cfOxXzIf3J9MJ4upXncoWRwaGh4ebjlc/M2zOB8trgxVykpwG1NLxIolwQn9RZLfYmE4UhAUzDFC8lICgQltMT9RSR4CyEAEF66dxkRnftGELMASjHv85iWKKGYUgEts0J2Ak8mxheUgzjNOj8SA/0j93uYF8wD3IAc2VeKIbpe9QA82s2OrkumrTLLTRwl19HEsFgjKf1wMxgPZLHPigZuvv6eu5sgav3z8RF3wg2wm40kVi6FkOvXN+6GukcXfRn5bTBY9h4ctuYTksJ+2CRysRYg6cA/iCNmiikJ0hAWmOjEjyrQqYdlQKUUMuexIXvEhDKcVMRAf4aCEepwBjnPJLg4vnWYYUgnBPV6zXwzM2oHo1OYkNjZgn43Z7FSnTO/xyhyq5gdsdln3OntkzqF7e24kBPCKfHaHX03klULBrtirE696HrjhrW9jHTUnj7/5U+PrJ8abN3vd2XQymUqn3Lbg+6m0ZzGz6G72/BYKnX1nOO+wk23CzcSp1uS0repiPkGUoBNcm8KoNKwVlER87ScXxnhjx0tFASIgG+AHeCTD2xonctMm3jcQ4XUO+lCw2DgqmBUdUUrMGGQGMvB2n06c08QrUIYQ8JvkI05b/NUdKtMCQoousi9XdQSQI0h3DNj6DPvGHjiRUa7OBNKv2MmNKw/VnDzSeHf4iy+6e5s97v70yNns36fPdn5bDC2GMiNfPnWn57f5ZzPJyaqmR7wcNYK8tKIQJzUSexYOVI3ZmNSEmCg5BTYbCyB4O69ucAqNzNoxz3HC1Kyd5yS0bRLKXuSACcRXKbzsNo7TZ0WR9TTJCjgypYZXzAvQduRdZQAvkaCYS0c7ljiK25YQ0VVVixgu5PDB0BI6U5X9ubnJqe38gFbdPzf5CfwXyJ9319Q/9NDoayfam7uz4YPvPipmwhOpKPBmJJXOZvyx75ozqb7oYnqwIjOXSE0Y1FeQrOpSUwT1CMwQZbBuoQm4NFAQwAnA6iIxGwcChRjDcPY8ryxIPPZZeCtcFWJLZGIeHImjoPfUIQZhTkxQqaRIECthUl4/WjECyAFz+OPOx2aRd7aADMLHXEu/nz03mNvWdQdCMDVRWx+fCxXT+dxMvFzazY09stbuvrum9f6G0eMnGk501G12bvR/1Z/dzLjTxUx6cbkz3ezOZNKp9OJkW0s1D1GIYAq+0+dgOMCrTCI2KCNuPbdFIN9u9fyLlcAAsMIO4HEFOPBHJIrBWWiiwBy0CT5rsdkV3QTRm5EYhe4DYoTtk35iGPtlFUphRAcVpmKEDcjOv0Ve1kkgToEm7PeDvpFQJloq2/MKEqvyzOTkfCidOhbaHE+dm59vGVr01D90qqa1seG+G27//OH2458eb/i091iqc7NYTE2EYDBpjzsD1WS7Oj+ZGM5pLkT5REHAVkC9Y4+zxfs0HPcyKxEguAq2Pge3fPTRFZgV6DiB9ulLs0oQU8wRHuiOOcGKYBARLxG3Yus7NoR3fNQu9lxYDbJzsE9pZVlJMEQ4ROW4KOtwRxNzRvj3D3oQ03r+9Uc97q53Bgcr+VlBn47MZ1999dUOd6auszfb0VX89ItP2+tfrGk9c/ejb16WPBh9rvn45qevtT85cSLT7N74ojl1YrPoTmc9qWRxu+Y0FGOokIiJ6CWg8DYHceJ8BFs1QRMAIyXCMcoKF88GKELQc2Ud9f3qwwgBD0DQrBhTRrBEVKHHsFBp68nUXxyqpXSgx8tY3si1jU2O5Xar5YRKgnaHSxJFgfgUkUrytoUih2js5qKhzIud7mJysCQ6nFPuT95/1d3e2+4+Wne089nO1z7vaG1srWm4uz7gvavh9OsTnx/79PXjxzY7ujPZunef+PY1Tybb6+7NutOTqc1o2/B+3jkdJ15JbRK1QpyjTslBJNjbSlWYFPMuA7Fjdi/lnDKJzBqM+vw8R/myLEnTG1YKYIFQJQHaCPbRvSsvmXYYDDQYMaOcGx7uTh2Gus6O5QbLZV2ErVLWXQHQfRFeDMmcuj88FM2c/mrDncy88pEi2vfap/Gz7Z3Nr797+0dH6kdfajzTUF9/V81bLz5u+/71bvfRz8Ovv/7pI/ee7q7rDn/25a2X9XaHe8OeR28Lh0Ph6Mj8q/O7uQUlssMhuFnURezdgqN5ExoxVEkw1MTlwAAEiJqZ+oYCFRhCkq4L0h87hAwESERRmMK0gx1QCbykcv4V55IXnsJ8Dm14uOvwcD4ZXQstFsfHS2yJlTQVbBitEgfwZVYr6Af39Kcy4eXnj/WGnlwv9OT9M6H2b8LuYrb5uUjf1Gs/nPyh9czJj6+refql+odOPlQ/2vpDw/Fjr3xw5/Xtdd2d6IrCe70wlnBn31p7xv3VeDTlXR7O+ctlVdbQXkHGJGFMn206iBPBONeDmjiBEkpgRGghVgBtUiL7ksOBEvqGf0lQRFE1tERC2fnyTZlw8QAJuLB/qUDxkh0tLOy3Hf62+GTHb5OLqenkzEJC29/NVXbLiZg/8IfNZedssnBgW/d0Pv9Q/9G6xQn/9M78RPZ0f/tBNtzd31D/Rm/j3U+P3vd462erNT+feulI55FTL55+442TjT3nBe5or2sOf7n9D8DRvdnt/unZ9ubeukwylE225XKD+6pzBeRRB2aoC1Ols/dHqpbyvmiXiOHwxwWEBIiHDI5eHlO0smIoKybKxMiPP4OulrWly3uYGBeRl8k6ZxdF8HKqyKWJ5J/F8WGIHJnD6NBwpdI2Em4ZbtvPa1uiPY4gRDiCejjt7ui///qbHhuabEt++9DmeK/nhYznN/fdnS803vfQSnfj52eesdc8/PgjZ06deuHx0bduuPfxzp1/Xjxa3+Bur9vsruvvXXQX3dlOd/Ygm/42WtnLjQ/uMaeF4znRCWOQ88S/EMiXVEZBbH89cDp0YuyVqolS7iwk1f2SViqVS4Zq5P863fnwYFtJ2wqsiEwMcMipcDpBhG0pik/JZ0ITE5nmbk/zYjKVjE62dD356unMSEvLvOasKEyWwSink8l0MfzhT4GltOenzv7m1HxXpjnbEk2mPQ1vLHiOHx89eebM2zVvP/DSrdfc8PipUxuRt+p/qG89Wfd8XV1dRzj8fLjZ7dmsv+tFqH98c3ysMpfbyn27zqSI396z6lQcoLkcbFfKVE/BaxSmomtI0YxSDgL3vDK+C9VUKpXtSnmutL920cXf5yYHy5pazcuaEsAo0MP8HKQEGS0NlLqG+r4cGdlze0YWQTrfbxta866EUsvzbZX9RDnvhaxZWJ13b4Qz7y3Yv/XUHe1uD2eTydDDH5yt7G5kXj964pcTx0ZPnbnrVM3bL7+9vnPd46cev+vxU62jJ9+470hd3ZdP/nhvf8OL3XWe7MRPHRA/+/8cOpcbn/t+0F9C8V/JaiHP1D80u6QIPgcakJlis624/Eppq1qpDLeNtRTb3hkcHqyM7baN7x9EdwfXC5Ntk3C43d3KXLmEkSL6AnaVYw4U2Vkq5VpSoXA2s5jxZEeK7XxxKBQOpdLF1Hjb4O7wRsmfVwNzZz3Z5x98/6H7j9QfeTh8omMz/fAtT9z5YcGYSx8bbTjZONq6fP9dEzW3P3bP8o/3vPzmmR/PPPfmu40PvNL4448v1G+8cDfcQ73uPhb9ors7605FxyYn26LD54IyCxSQ1w4gm92iJCYSatOCdiNfcsXU/VIuN34OqJWbi4K95aaGR95p210BugzvDud2d9+ZmpobbNkvK5pLp0AvXSc0HnFuV7pScPZQCIIuuHwxOplcDKV6i+lx90+T0cFKKR8ZjraH764/63+v/siRR369/+Tokfv6fx8PkPly5cu3G88ceenOe75+/K6X/qPQamPaKOM4iYmJi9FEo9MPflODmshLcls4ozlkJm2QAzOujHoOS3sfWKubtLYj6ws03HmdHD3BWkrLCscdZCCHpTtkmnPQ9gBD9eoGAxLH2widvDSSKZMMFx+f5O7D3X14/s/v///9f8/vubxhG41j+JzBhJphoqZuuruqqaqlrqXH2vlxQ21Df8/lvh6waoFwNKbI4Va1DLjRF8qeLi699P7Mq2vzR6fLWvOBdb3LXwIJvpsV2IAksuKoGZZZHuQaCEwWwSULLCswKr/DrMri6kLl8WNll47nA/3Wlrh9RQwvzncYPBHjeWPHZEQJh0G6Ac3u7HVFo0mVXVWcuZXOOn2Xv76qpqU2aLI2pdP2ifrbL16KSNR2YoK2jy4um2kHmofrHBxGzHWZSQ38vA+taW5MN9Y2u5tnDdXNl5t9vo+Nl/ujvVGnk8kkZ3daWwEYxy+cOvb5v2BHe/XRo/xzd68kHm4dXiirBNOUWDbDCpKYenm6j2VViZeoHM9nrqqBLJ8NMKKSFbP87sLXxaDhPnm6+ELbqcrE6p4zMjk31/rQ2NNi1Vd0RoyRiDNk7Hc6+9ec4cl1UV6jXJtD1uGtKjtyscYadBSkgy30HOrfWbSGaj3tJGm23R4z22u4PB1S8tQJ3EQ66PxHoy+NWb22oL8+tFyRthovV+ufOZr4vv97Yx9gGeBHryaKvsz/9NidpfyiK6Wbx48ljhUV7R7s7S59WgroixclRmDDARBFcmYJhCWLAKQZ8FgCuPAiz/CrDDW7l91dWKjMByeqp2Y2jx9fyCZvRoY6Zm6FLlenSRzV13UAFdUwZACyfdFlPJzOqTvjDR5X3f4tm25uI9fihQ+xYNBkQv325UN7t58mQbmbaZR02PN0r5x8/jEYMzkc2+fu4aijvh71HrrtduJ8bV31V3rv+XrXUDTqGY8oGfWHc0Wnrlx9+ttHwPf5tfWZ0m/BOV1r9kA82OVXRZ4VWGZcEAClCuAusEImJYqUzDMsAIxiRR7U/zrSaFgFTLeaLXv33VnEO7JwsOFMphom22+0twfpevegyeaf+Li5s39F3xMy3sh0pBpiEhXV16ZReoC7faH8R/LR424H6SANaDPeaLfTZPx6I0mm62kzmWfKv/u2JU4YbHS310bQZj2K+k2pisjSmYlvzrTUVneueHqN/4w4YwKbWzv35cy/V189Bdjo3NLZ45fazj6Q97KtP/ywlz2QWJBkDMO2O5mwFBiIgdAyGZZl9wIAqsh6bjEUpkRlIPHCGgBJlFU+UTSf//iVhb3MjYFI083ZpKtC30w6MHzbRyNNnh7P3fLOnsvRiMsVHe9rrgqiXV1oTRAMP6ZDcBvqM/j1mKObS3PckQH92Ww2O7A83xOPhpF4HHHjcQdO/0ybTWT3VHBiwj4xVDFh+HF96GNXQ28qFYr8tbw/lih69vQbpXfyi0+D/Xp+cWlldi0n39rb2WHlzKQcDgth5mqOiaSSX04yQmCKkVkmxmd4ZadVSs6KvKjcudSmZu+oYjb722+bF2ba9kSWCiQnkw3Gvh4rqSVoU5xAfNum+pqmqvMmW+eUES6Aifob9GGNPYia/WmzG7UcoSRm0XEOM4fRpo8+wmmORFD4QxAMQrjjIBjcNmdrQg20e6TL7U0TJWARrPY/Wv7vnuddhurFBlc0URZpTRS9e/b0+0X57wIXAxwJV+6qiijvqLKqKvsdYYZhwlkltjILskxSZPBOYMHEJV4QBWVWEXNZlhIBgOx801KWX1DVA15KArfBdTPa19c4SsBxLo4UaC3dNu3mABpsv1MeajiJQESP3+8n06AyMBQ14XEC7nYQCIRxaBxBBtumsDdtR8Nb9zgkTwsRNhvusOD6X2CLheMcNea4I/QADVpDLbXnK85Uuwzls2eah4AJtRLdkxYSpWeLK79+/2t1oTiRUCtFOSmJzD1ZGV37oo9hQMUkYwpFMRlJkqWwLPErFC8BgpaEZFLOZHhpZU3N8Ucv3GFBCfEgsvGGqSEgAxt69KNaLTaCF0AEDF/D3ORE2oGiU52vvWmT2vxm1OOgaxxVXTiG3LcMY7/8brlPxF+vipNx0jHcOu8bvU5AeJ7FBiGcBcGwwRHdAO61oSRq6LKnrcEWu90etFbXpho7r+E9nT+BnUAqQO20JhYO1L2sml1Sd3l5T5xtlFV5gxFyZ5coUPhh0CXkAOU0BuYlgQJjPSPEsqDPSFEFUMSKkgEOI5tMZVSRV9XAtBSIJIe8+vK6jiq0Cx906yy+rcKSD0ps3m4bzvlbcGKx7NlbqDmNcXHMMegdbrQhnDa+5bPgCPGnHsEQfN82gl8bvD84iOVpaa0PdmueesWCYQRGxLmPHLTd769K+4FGaPFbz1S31L0/0PlZKhQ19v59M0ntKPJkLgLWfHeVp7KKmnBuAhBkVgGRgDRjepkwNTB6vSMgy+FU7t64AniNyUoMJVBJSsqIuUwms8GqQIJnFYkVOjs83hoT3bVPYxxEjHIQRCBbR1AJ4ZgzIeYzlmnwI2692cHRpvq49jYX12q1J156HRrWQY74veU4MgL53tNq4ac+gGA4b7vwIqzRjv26VWIhYYx0d2+77UCmBauDab89XeH3VIxVpbwPhzw9i0P9QIiPj0c6AmvJ6Qif5VVRyrDJPqcsZSIMIwkMCCfGMMo7hZj2+WSMTa6wUVmRJBF8J8fGmZzY5xRFRVFFFTTUDcAJEhWarec+0Nr8g5AGQWBd/AukALr2DvTdB8QXkIXsMoMfZ+7S5MV/5jic4Cw4dAKHPpme1YKBYJAGBjmp2dbAJz/8zlcynHdR60MKMEuJVgfSEXmIYMNarNFLpxfRtN1Mc/6H1vSUp7yjujZk8vTcdx0ajb2Ryb9vOgMsmBVILOfOjCL3NumoMBNmAQM4w7H114einufGnRFlMhnuvbEoA2gABuBrRs6Ahs6vZJTZzKIsJ6lAQ11XHHkwY5uDlqZhi+YEphnECsfeLntwAnqqEIa+c3Pz0zigrQcW0hKHEdjy51s2+NrMMgzrcC03ohsDS0DoLhb88+Qonss7+btGo9PAUBzSFECwFtO6R8xxiEYJBCUnBvaDzf4/Jsr18+XfTDZVpDzG9RHIZuybjERCgrD4xX6UEQEcMeevi5QihAWnQE0K4d5NYCp9Fw2oTCyQCS23y0DnpO5JImg9siQKanIjKUp7v/Ebub71b/SAZTGsAB+B4IL34JPXYQ3y8PfCQug/Cq03pnEyDhOJRhMzP/nJGPzXqCT0fT9c27QJTWMyaZ23sIQNYRAcsChu5lRQinackKxjJmMIqQod7g+OmZs4CrseU5ARNsUcCC6LeAm3OCUXJJEcssW76Knv9U/SNP3QJ8/ze35Pf30X2INjysbEvIOJ7oHhhUHnIOEmHO5l3kq4F9wC8DmcvRxwAFu7f4EheJ6iOa6GxqHAD/h9fhsQOBuznLC6zIc2l/nkHdfQS8G3tvtHvh75vaWrxdQVutkz2XP77LVM+GKsT5HldqwDGCpyQFX2tXhcXgtcVvVpxI+mLjx1/6GsSuVSfG2t9N6JimJmHhXZRNzx1gTa8psTe7sTE2pelU+CHb85GffwqZ+3JSwYh6+iF7MznBujk6t3FgF6H14YTnMpq5uL9Q4lTgeSoqWY9g34UrzfT51REEIrxzsFomjj/DXkqZtPA4Yj/QM7BpvPuQz45fVu7yAKPDPoE9SMph7To23tQ8cvtb10ZbbdNH99PRp9w1ONSv5fd7se7dM0XdU1BXVMLSdV9wLIBLS99eK6qoa/XAvkA/qaehkd8md7qOmcvJff++MzlNS2Nicuf7an6rPrM2cHQ+sdKdbPMNg/bNMhaQcQM1CdS004oPm/GfrqP7bMuR0/n+I7UwRD3UiLIuunGQCAQAPK7RaMooGw2SBGwJoBnhe4lLiUZOx/L7jdfu6vu81m2RzbNvd/HFz5OIgCRPNK28rUB20tF8rrHtSqi31zpQ+qlfHHH6hZUiSlolU0Wa+ompZHvOhqOaKrGiKsoiNzi8d3A7vS5gn6IxTfy3+2N6Hu5tf21tYuX/t1/ySg6B7TO73esZiVczICT7FMJwBU8SpGQqzpmEwDcXn56IxLfZLMEPQdKxhmFhFtzkXuhtuGQg2kIaQgxX6HU2DxDQEZwDlqqRMhtomnhMXG+NzMwGDMvTzo9sbam1GjGR0xt/YHg5MrUy2J799885Lng9l9T/TKBxVdGz/aKgUqd5mJ6HJc0rSoelKSAxrCFUZ7/NSp5FH7lMZzqppFK8GUy2sBdS0wXDqa2N3d3JRlVZ28M9sVdHfERAv00YCneSxtqTc2knaLgWRFnOZxLskQFJMeSCWFUxvtX7JahIY0z0HBRvC+Mxsl+hKcUQSEDQrumgMfvwg4yPnFFAWExVU+3RHj+djYDffgmMuFstq2ubt/ZiZ4tdm0OfTyRy2eqf43Ixdmr4x2KQVULeOSooX1UESvSJFwrrxZ0Iv6sAehOZyPf/f2pJrX1JC8GdfiAfmnXADVkLz/Yy4v78rzmbTk2JBCnpb+n685AW08xCCFgVQ9ewviBoYWkiyBYcjdhBu2U8Qb7RZZGysSbOeBnWdwigKAgDaSonEAUc0IkKSoGgGINAk5gRcXfhOFRcJ2Fosd3bYOWr1jg67mmRkzihKfdI++P7RiGm+5dOHDTyBI9M3OXslGC1ldkrKaXKlI8lt9hVA4hC5kyRN/bldTp/RIAI3fFTUb13UFSXAvrgSy43FZiUf35JL6ZfHBo7mt65Pr4+VL5mE3Rwts0znyJgtJwggZmkt8i5MY1pkmIGCMvLF4w88A2CT6CGoxSQDiJgQ4RnCZRYjVPorTNI5DEsIanOXsD6NneB4IIkMQnH2BS/VanahszANjw61er6N4+nHrSHurqa2l70JL7+c5/1RbzzcfFLSCJikhRZJ65I0/1kNaJOQwlSYv59FIvktV4oHKXQyVQEDXS6opi+SYP/lVUgJiwoTMHAHLlfZNt/eHRrvMiWUnYcFXv+VxzEKRJCFQACdpaG9qFCiY4dMWREPaDcCZXUweOKAFQgIHnf8sPO9rJBtS19yQpzASo8maDMX7fnsSwAQQ051UfVOTxe/vSPliO7xr7HZvcPAO4ZhJtG7frZ6V8x9dmF555peuKc/sAB/RoyEksNBkWZdkpJyKtH9yvXxeQwA2SgoyBFWX0HVFl2VF27imBPRIUcv/Ern277WAqoZyemh6aH36raH5LtdMjAEkbT8TSCQdiqZZTLDX1+HPPk3C5DAHLCRB08CYYTlfmoEsZlnFSQYWjzppCAB26y+aMtDkgeEYq6F4xvcqKZIUZB4Wl75ib+44UjZacDuWl2Mzg8uu7Xlvu8u1vd0rwIeH2978+CXHxfdNppevJr7RCz1yOLR5vWcyrCuKXpW13Bu/9kmaqikyMjVl6xAxoyNwVdRzfpR1XYrqIU92c0+XNal8UnZsXro9NN/8frOjl3MSd6y8nWKpWgwu8oKRwgzks7WUY+tt1khCEgcA7OCLhI+kKRqS9RbwJE42kJ3w1bomJwUHaNJOgnPHNXWNSGw8zznBwQGTzLxqJLiU89iJcnRsbMzpuOsCXu/HZm+djahPtpxvGxlpOX/x5dn7clciVSWMhkOefSmrRLJSqBKWQ0h2SGEa0p+mFMK6pEgvd/RKFa26Fc71VBQpK0XL01J4f9oj3fpqcnp+pulqV7A/eHPB7SAAncEaiyJMAcyC4TjW0P3tQ9/VrYrYASUyfnhAExgh+oo3MMpnJ5+04J2Z5889ees6jUFooVJCPcnWYJA856vtpGmKTVpI4edGICz4ndxyhzPh9Q60xjpi3u13vF7L1h+mR7db3/F3NK+cP9/WNv7WxUjVE/llPJsthXo85XHJMydFJL1QqBYq6FSUaqFQqVZ6br34o1ot9GWjuZL+Syi8L4Un93Ph6aNq9/r+xVEDQY60vt9vZlBWbjqmuDuHIgl3MLwWq4erP9zzaSPe0EDyAKKbJA7PGoyYERoerSXql16ABIkQY2mAi+km6BRqaarmv/9Io88OMhS0gIzR8jpvswkEgzba6uQSy7FWV68r6B374pF7b3qbV7qf6Q2uNL8/v1L2zPVNXYhOeXo8fVlkYtkcKp+NOVNfqID0pClSVbkLKhx6Ze5PtKCg3J7LRS9Go9GN3NB6tGlgenpyaLq9LXn24/FwMOhMemMpK4DWUx4XsTRWX0sZDAas9mEkJEMDZO1OH87yfB1GPoGx9Y9iYm2jxbdK00UcscKyOINbMunjTrbm3f8eq0PWsAOMZGqHtVO8mxFoFDwdR26GsQ4ODrpcaL42ZjUn3mmdDLYGp0e3P3F6zf0z1pdXYqlL89PRnnIk+slUruckFK1kS+GqEi3oG7eiJr+tUK2G55SCFPmfIysLbaaKwsV58cULKjNPXmZMHMZcmEWYhQnMEJfJTFJbO2BS6yTWpqmkJnFpY5OqrbYYk6pYsIixWO3fglVjaUj6YKW4oLjwW8QFF6jiRpEfFLW4YV1OzdJCOm3n3HO+73znO0/OfXbmw6feeO3Mj2+89sPXm79/8mT/yptQs/d3L7q6lZt6/caZ/ER9+2dPoTQAr6u4YQJ8a9lxscyiYA/J0AJBFCQsjexShX20i21JScf4fb0DDV+PWgnWL8SkvtC/Yd5hERs0xLiR0B3TTHkgz7R2JtaLblRTvWq1/l69OZ1fzc0MLc/mZxeHi8+PNaspr1XrkIn86Nrxo+tnPnrhzGNnzny5Pvno2MLkh7/+srk+TmYr5ocfrs89uf7a3PpDz4xvPrP5bPssTETjT74+NTrw6Er/yMjw6Hujw+/mbmwNr+Z6WxP+O9tYl6I84jsNHVuKUQ7ccohYkAypjSTJMgETxA+VUdx2iLLnRokpeQmQDxLfNeLHfRQqsAd/O1ISKLHsJzQ5IcsxuZ32PKInNtKljXoJDMJTkw189ve2ikOgbWaarY0LPm5tXfOyPTbV/9SjEMnca5+OT0LpvfnBg898+DiA5qFrLznvu2eeeebXM7+u3fnYHOwTJ1/746bPHhrvf3Plvifvu3FxYWBgeHZqcHl5dfjGVns+l8rk2y5/fGtXNwhoAAWre4RQIW77syz6izdc/YulpagpIQrvB77iSlZWdahANzXxoFYLvEAhel+cqEjkNd+ynKwamCZIUa3jtU2ZUVAknc9sNDOZ3EwRBoJ6czX/6kZ/t9hsVtO93GC+1/4pk79xZeWrqbHxZ9bHJ/+Gfe43b6w/9CHk5t4PH1r5cRLWopPr65uwhDtTG3ts7cfXX50cGHny6xeGFvtnhxe2Eumh3PDGUrE506qm0hoYM5KlIpUgx/D3MKGREObdP/bdc2+jfZNHe7yDMJfMYmKy2KFMJ77voD1idgjE6iYO9D6JjSAUDkPNKWEWdIFThuxo0tZf352z7uaXuhMVslUFPssNFpuLMz8VV1/NzWSq26lqPTOfH+vll594bBdObHzy49c2NyfXIBMfT45P3jl+Zv2XXzfnXtkchy9rize33tmZW1t7aO6xoykwL3ytcv/oov3Wt7mUrPskk89VTydDXaRU3EE8DijJjEvhz09UqmD6es3Rze19yTFoivq7i8S/C1mJxTYpOLrtQmcxGYH2oUX1kee7JA4XBSxFHZhxRLF3E5DWhvft+bc6KBFr//59qVXNZ/KZrWaqnp/YBkqIefViNVbSSulefez+hZNLr9lam9y8c/aF9ZXNybnJHW1obXN8cn3yoevXHoIfzGn1G0Yfvv/1+9YG77/vnT/nRhdmX75qYGDmjr+L9bPis98cbKV3etpnDelA4r+iFF13JIIpUtO7VlauiWUXIx/9hQ1CHJV2LcCNXHPLPEe6vEyXkVVW7b8aZeDAPoIoT9pndxk+TDGERTVdiJTSsuxpzlcvy2ktkwKXIXW2WK0+Wjm5cb56tlo169HWjZUeGCXdyvzZG3OrufmRh26+ffjjytzc5JnNm7/65vr19TNzH26Or9y8cObmp5Ymr1sbGW8NPfnoG/3rQ/dfP7dw8w9PTi/P1+uwmkh8ftPn25CVXYPsEk8jPObDoXKY8CoqIwA/nDNFtg1eIvukG5K4jsgSe5dT98TvuzxP1bJlCu1T3XgYqVZfgaYwDqPDJMbHRxY6uu0Yc7IBuUl42o6XKUVjMOWk5JLhbWTyqdZ8L6P92H9jtd4EvE5E/0q3mvVz868uDLx0+/Vvvvl67r6VO9emRjfX1l4Yv30uNQI7noceeuPip174ePSp0f7vR+4beHbkzoGF0eWxxa1HB88MbvR+HpsopWI1cyn68/O8LBnhbwM9WeAwESjMYUqleNlERLSw4SC30ChYiN7/iRURxi6SkI4l7LhqnMFJnOT79EgBcSRyS4hQmOXD/O+XFZAO3VbrlqJaWotqR1Ytik3F+qn0Z2c1vZvL9x5uz7QyzZ2ldq1bqfS2K/l8xcDF0evvvH2kf+WG2bXOwe1ra3M3fvrKOysDA7Af7b8vn8uNTS8vbA2OXT/UGh1Yfm95eOi9+gw0sNFqqjq1o8iGoaQRiH588reMMOY4+pgwmKLLFu9L2I0bDYpxTLIfZ0JsgbCHpuL6VgIhhqYAH3FM72Ca6+tSND465CIhxKGCqKvaH65qeKJuRDFnagnNM2t28Nt1XcmMpRKpBozqsldKTYA2rLXldiodnJ3fSKH5JfP++fTUS89CIxx58837+kcSU3euffrY2gt3rt08et+XU63j4vLy7z9df/2516fzN7xXbQ0Whwenx/Ibzw4OVrWdqGxAf+F1JFEUTe/HPxBZXIjjA4riiO/sYRsz+ABzCMXVeIfhCwaK1yhUdrD+nUIMyJKJdyiuD2NMZ7/okvBREoWTvBEPeEoWE3LM+K5hep7XiQJXf9uQl2owpwY+TEqlhK9JQcLbkCfkiViloyBZu+mmYOHN2aGX0l5p4Pr+kfH+sY8GV+4bGLg+NwjJWRyayeSK9cGZmYX3+ltjyzOr+USs+V69uAHOXHUrlUrI0A5NXuRdnqeBjpjDEMY28G+SIgmLZhAi2S6mgmMHU5woNRQO07RFg3YJi3YZIkAOg2iqD2oMw2kQMU4okcKEY0IUD+VoYEM2NecwGsAQYfjBrmdLUtY3tJguGztLKOalZd9LpDzv+b+ipfTnzzanXxpe/vzWN4emp6cXRl969/r+hxZGXjr7zsoLs63FiWBjYr5YzC0uD9Yrf03lS6+/WW1Vmxvw6DVShiDA1MsDnjnWDvZV7lAS4QaxjIiL4DvGepymszqQHGZOklhlaR0phK4lu1iiEaE5qZAtc3t9ZZGzaDgIEqLY7G7gdihMKY4feyQuyVrbiy150X3FOlAk2zyrHDigAx3l77uOoq4S1k0/WmrXYrK3E6tDFcGcPbo88wIoletH1gZGbr7+hpXB1o0DQ35iMNWeWIr1chspL5+qljZamdLHQ9tb0WpJMpd+kiPgPWI5UMLffs6jOAtHznGYcyjMCBwJYVrJWjYVp3F2m2BBpDlKiDAu4nwd5jeEkAR8QBFGEPsIBZlrFFChI+67SESIE2hCkKRItZruBEbN7ugHWcPzVaOMAqlh+rIpmoboO5Qoa0s7WQ2sqspGbvgGTduI3b+4OjQRU4qjLy1Mr7yU/2ngg9H7rSVf3tppp5cqsTQVjdqZv9ZSg2BUzseCmPfFcS/qHXz24nPPW0GWnCCi4mTXogHNNGYYmqEIJlKWdI6QT5jT1v93kmG4uxWDoXyZM9izBwxKizDEoGOO6QP2E5IQNkUhvWwDp9M0R3hJMduNAIBy5Aa2LIV5kKs8IwWI1y0s+6Zx9PKLJ9quWTO70Uxsu52baLWGnk2LrcXW2NaVxzPTCwuwDnlsaDE3NFC74u1sJR20t9tBov3i02/1plobzVS0mjK+mN8uaRmglHO//w22SjlgyzyikweEpx2FFoSQzUBAyLWQSCAGuFVMJwU1THWff5rnoOQ4UKAHKlAYKTum2+gD2jsMhZI8TXCIit+N0B9usE14RcpGjR0DH9i+ZjvsnhU8ckR40LOhbYqAn9g4svZKO9HjLYMHRRsttqqD+Svv1YZm8outxenlJ4YHphemF1dbjxVnV7tv1drRtgaWvAd+dqOUSidMKVoCV7gXO9staQnPlyUTHVHxJIsVMV6gCQozmGOYcJLlmA5uqDQXfBZGGOR9JBAERihnCQ3RsZgzaJQNY+CDEOb6OA6C5yIRzqZD3x0BGxzuIwqLDV9CtsIjrMiOqxxEE65vl1XkyJ0Xf1YsQ47C/4dJyvOQZpAo2AV/rea+uRDyMrg8nJ9ZbcuL900XiVZcHVydz8W+75QmwJ9vL0Vh9vOj0di3Xc2PguEN1qU3T0TDly0lRDFYPCSqSOmEhWKHcMJCmOq4DsN2VQAKpjH7h8VE9oGxGDNbJgUua6kBTYXdOO0wDaGPpri7I3iP3A06IFwOURhTGN52ObqzR7Y82pB123Bc6AIBv61LOjCoISletvPH32BatxPaPe9LsVIKnN10MXe0DfwLz+hUbbD9HjWBYPLOZLYm2r1YopaQDQuMCfiD2l605C9BTNHGVFcjFeQoOmcxX5wgjouLLEdzOnV6xjTUEcsQgUblsm2Lro3xPt4+5oSOQtm4rHBMAQWIpWwuhMsCq/eda6iRu+nP/oBfBWFDx6lQmSIqnzW0hiE98kAgGoplSpSpyzpv2H7c3TEs3eEbpi4aCY+WsXm8VWpXqr3Zocr8fHOwuQqb1EdfnJ15deavB3Yz7cz8Ur69VFqqgXOa2JMbu/vKiVbyrN2aL0e94JqDCfufdHnPOujEHApCCmgEbZNHHHCzLJpYUFVLPaLOxTkuyQgHBSyi0J7rMnGFcThBEGiBwfQ+owidn7J9z//+bZfhGApR0K0KJyKNuXKc5uOBsy/HHJG1XBGGV8sBoe12CSKGxVtig+d9MZqoSe7Vf6XljQrsG3u9Zn6jms8Xm++1lqvFTGv5vdzln9fr9YlzxV5ajvOyDD7XQboWmJAdRd6W/N10KV2KGZ4jy3bDFInEWwVMU2XHVuMc3C8gIBwkJUpltDLFA7vZexy3j109DoECYiTImxtxRZ0BAcMwyO7jMLAXo2IGfwwRIZVWEYMoEXM8MiQJaM3ZE8OfZyUbSfyhyCOx4ZZF0+cVTbETbccUEax5z6aqg2AWVDPVTH6+CMZuPtd8b3CwWYcGX9PapQn7k0d83QTC3zZMAsOhCdMXLI80T3P3tIbnp8M6sZApOo74PyOz7r4IhQKNholQwFY8JpTPuifwiZilpDiTdVCEY3GEiUQY4e7I3Sy0JLYPx7EIxBAkaZdyC9jm9hBHE51kWS7iiFJWZiWeZcO87ds2CDRzJzixpAKEpgSB4wTix125U0pP7MRSeVjx5usT1Uoxld/IVOtQbc1UEQpMaZQStm+52z+JZixIsJAYNQt8aYDZ4IPnpSJRO5It6NyOzTI0FI6YBMqCB8eorFCgk0QXBHQOPoA43VMknVqEtBuhRUEoRyI02gsJHBL6wM8BjcMyGFucSui4xWLmbkgpTb4voCRvv+OQnY4EXVc0eIs3TcUE5Ch8mBXlgsSbcU3e8rRUqZHKVNIZMI23VqvNVuVsM5WpxmC+7qXbne8C3y6Yp1Z3oIH9evx9QrEU9NNJ2vZFU6Y6dtcUWZ7gHY5SCQCfwdDP4RFhgNNsJgSCnu824mF8EuFIUuT26DIpY6dGhyMR4fS1/dFPBK5m+wplzJTpIOxSB8CHnMipb//B8Ogc5h2H9iVi6yz0UPXcocWGywhYM6EoWXwoiK4ZfM/KjmdENdmOtWMSkiYqSz1lPpMa6+1M7KW0o3R+dy+W8bSDdBAokqnZCVYBaSzBuKT//DQvQh2bhn6Y3eUxTVwax3kOYqEgNUgVOCZyd0QQTl8gBBgKsM6dZkY0ChEuwglxxEAkHMQMueToCFRcnxhWKUHlT6+jDiFNmA6FQ2oS8VCmOk0FYRDlCO+KvP2zva820N5BIZ7wj1m+pmQbnlyLdo2Y05DTREtgoxftfbeR6qXTvYl0JVOpNEtRx0kAlwDQdFBIAEIQKJqiQKHZhqTznx96UqCGrS+QiEEAnKYFbhDiUAVROD31rMBFOsQV/oocRli2A5pMEFQ6ghEEyTT+iGBRAMjQAmZcB/UxDnEBLUzDYexwkoRUsN2seNiiiIX5c7QFDb4MedNDPrCNgRqobPnY5BHacWs8bxmSb0TNnSw/++OXZ2W5ovUSsEzdWppPGLEYrF6XwNOCZ0FONlS2hkCvfolV3UdH4ERImiQhvgzpR7ecohzRp8EAWHSBZSLbQSTCMgy8oZAw3DsKh7CQhcOoUZEkf447bUNCyArfHQfYcI4gxP8j2WpeHCai+MK7v9vMbZghQ4gZmDRCmlIhwUsSN3jpQS81Ny1BDHhQXHLwJBQv3v0TRBZL2Uul4EVQkIKiCEIVv1hkQVAEFXZl/UWHNt9p38vv4+V1sxeDiKjVTWQt9iW90jazLdX+A3y6YKrf53BVOUGUUOGcJgpK/UFhdsvEJ8m+v7kOeZm/f/nrt598+fd69vT86fkbz+F5HHQO+qlnnrr5bJaW4X1ymZR3uMmvF/kfX/nehRWssaxCSJ+sLjgsyEj1Hy4I0aoYokb4mOENCEaJ5PzY21Zi1YnhIE/yhEMFiUqvbyMwDq+LEccWuvTSWJkNQgil7jOlLI4iLoVvNRQT7tFpdwosZXaMjMi6cFXq+y7lm7VKFt2Qo79C77uaP4NWCx333c+z+eG5y+3Tr6xmN4AXzYhLn0rIVWF6ZF4m5aqiUC0ZQwuSp8xIAVwihYAM3pPrjiYc1/t4TJJGWotEEDNxJoMwEtTpGmfKyE3p6hR8vKDIqPFGSl0JY896GdUCNUk+HRcEOBSR24qmbxX37fr3q0gxh861boRDdfvdPHEPvyc6bXFHEOY6XW2fieIQHf3V5fOvXS2fKfNZmS+hPLecFdfbRfrb9VylvL1Dfrm9zYvBUYD2A7KH3iF4g8iMtIRkVCPH5p0xGqm43RKEMVaWY/ZSWZVowyoGEQdAhzHh99BexNEH51GqTF7TZOw8wUzKuMgLagnVSCkntGpVo4vX/zY2r70ikcxZw6nTWXnPCwjShd5HmsSxDF56SfohvcRfUBd47mC9W+Lm7o/Jzpsixy+mYXhu2OF6XDVOqazN4/hYtCo0j9MYFRCZTOD6mzg+0eHD7QSPjoGIKaB0Q7FkoyZgxETBAG+Y3siSJpoVUXMWEFpWq1GL1ohBrFRIv7TGEcmnZqM4Kugf24tQBcrR0IdOPr2Mg0LrZpbyYQGFRVutnn+7jHgX/fVkkdZbdKGrV5Ylfry/ScpZNXBVhTdLxNGv0BE5p0yaaKrALQ6VAr8eH2nI1OPkxkKhvlzBXmOsIdZ9WzTjSBl01GgIKJvcOsLOyRbAzHLdYgvGhYhaYCRMocAzs5Z9Q/2VcQ83eb81dP8J4TpozV0rWFGgiEXAnf7lBxlQ5VDrdnC/Kx+h2n387FsHvVs6F86TYhUunrlKb1Hbl1fFIaxVuVhynv3SuQjPIC3E+4tJKwxLqr7OlFfx46qcw+EQPkkbt1oJ9vEokMs4IkBM21EAsj6K91GbafU7IDvbUaLI3Nf/uYW8MEq2v8Wklf3iFuJXo++S/ck1oRBdb+n2LA4g6ZovTZMBW1LnMCDq3tsz3/g1Alql+5fvamz69qFjqtJ1n+qBknKxWC7SU5fPnpo7pt/zQe97UjS++HSIan9fGlGdKJDwTNC2jR9F1L3wUiqVzEYVY4yEBORYIxuAcBxbpCCxLCGnVsWdxVZ4H9YmwUQQyQZuJs3GSKOMEcJn8dKMKDeKVcZmLYZeL2qxcD44kxJ9NriKDI+KRbnOk3q1bua+OXzbLA61Zp/zgZStXcDHtU+TP1Jd+HwWVvNbx5k+s+JMRE6SQ/hM4LH2YtEviPD9j3cffPf5n9fgvvD3Uy5cI3JkgmnWYg4Py+APY6U7ibmUgOv8zYOL4szstEikRjLCwA87MJRbJeVn9yUuQ1MQMQUWX6q7QGJZEUZoaS0C/WMQJs4WybFJrlZOrZKV87QSi+u9FRy1B3KaUYSGG61zm+ZAGRAmQ3e85IL6d98k0bheqYpcX8SREih9o4kPT+KfUPYxree2BasQvsHEBNFAk3SE5IiEpKjqJyCAyQRIG0nRSWHZc5PTRYNewEBzUggHQ+z++UfUksmcqAQWTUYbfYys6BzFsEQRGCVOZWL7m2QNxaTFutG+qb8vlutZWNvNl7Y/HcKU08Gx1ce1DcNyPi+eOq5rWl5esjt8+OplADqvXRiyMs+wVMRvnkD94O7TOxlBvxqwABC1gz6Qk8V6JBF5E0EfmP//wgDjNjJoN3MHbg0njbb5HJAGb8MT09kqtSq8VqVtvaE+6DoK9Dfas/XNw1SvGkq4KJLcRqyk9hhZUfsiWTThXdkG1lJnda+EEA+s+6oIMpsucWGXC43am+Uz53i5rtwuDV2mze6nn1oqtt/viWho5FQ0BTLgn4HG7RcZTpxe8ZLZgljTboSFxJt/qk087ZMaXoodk5TEhQ20IedLzZmvtaio5p4liw+iuhRBEXAge5pSc6eF22T1oc7mrDSvfu/iPMsqW4igP4ZEPuSs1d5aG2TlR9JZ6709EmpPPHtbpF5zWOuT9w0VlhmtKgdk9d3ZkZp8xQDyiMEQCCKSNO4MIjVYEazyaz1KguW2rRwwE7LvIZzJnQ99IGcdi2tjzD8XxAF7nIhP7FsttAcdMzBu32+yjbHG+I3Xm+IfH1R90QRZvRG2u6V2+9PO6k1gd7q/plOja0hcB0NlNcZ5n3WcrXy9DXTQiW+faI61NnYY6hANUx46qy03rbfBBgsuCDZiIw35QUs+Jx1kHJf/cmj1rLEbUdRw+9uNOjHDvYhlBSO7GNY4IJFGo2Q6N2kWFWkGFVH/cB1Y8kcSQghezDYG1em2SooYtguYkCrmFXnBfrycjfwlyTPje84954jxLlQ0BVdK4DpSWex3PB1WuoYfHOLJYKtsugXdKcdVUQqyv3IXVozQ4u8M2mTEG3raOUm9IOMyae7yzjgnTuI4kbt2VvX00gyWcwD2LoUuqoha7kWTelUfxlOIluiyTr3n6PJMcmqm+s+xsTppv4HV2HssZEVInMF0FoMSgzG2KnEYh18UQBcyONZKGPCK2ZRuffiYnLNxHMzb7PZ57abFda1jYCzjhc1c5N9ec3px4QOvXBZDHCQ/F5TwY3H57tOntfY2SggfwzgF5O3BL0fpYkicT9CSt3BPsglYJMVwhMeIPi4Lx9Xfb04VU0YJt5QAYSdbhn2FgEGjuJdJCE8JVLsxriWXFUQra3KB86TGUnm2dI/MRr/W2Kt0VOhUrJ2xAesUzERGbEk0Xoj/bacpmcKIaY/OZTRHSOnoKZNA8av6m8tP/hTPPBJMA50sqFl1ay2NWWzIqiyjMq4Z55psTNdaUlnPclxaKxhTDtLHJfZpzbLqv1hnyRqGMTtHtAp94VY4rV5cK/7L9ssulFOcTIQ8TLEiHOaODQbB5wz9OUMvsFmh6wxjtYWrjIpDAKAsmyS22UXwAzRBRYukmf5CmeTWFRefHGl+1f0whXT+X+1hsUbWMkUbZjwKyIqVFYm491DbOUkevr+mMhliybdiKds367PIoPR5wY8/fpAybYRJyBmT8+mf0WW3Le4n43RYfthmByIl0+RB0oMGMiY+/ZPW7hxaxW4sBO4+hxs+V3DF+6kAQHiGJtZWJPZ0cLKHbinrKYCns73JTqvfnwTjB4Ok652KtxSH1E75OUmwhC0ewKtA7Um0f6/WK2nNhattOxxuYwSGg8ikAEair/c07+NMxwPiKeohFD5nAAJdA7IehM47EpfjBJgOU5ipEerKs4dg63Pa1SuaqHWmPKMxLZveziYPHy4gdcmCRoQzT0p3WJiUaP+acSaifv+LOCcibVj+bD10cCQEV0IluOd3fxIJWvn0oCTIMsASazv6easttw3MO8JMvW9VFcs9/z6XwsGQKfQS0u6dAfMmo3LpNIJDI0Ji3FLcORfAcjZCR6JKQBwXrXpZuWvkxVltZymd2cc0EtILtMFRXq/+38jlp9ezdjU7TYRxOKWv2ThyMg1JxIsCAW/NOIc4eiEw/j4J4OjHGWAiRWgP9z1v/+Ir0g2jHKUZs84oUVrmGsee6K7ahyIUFMaASatMezLQfXGXo0BWovcuSFY5x3eldcNF6GsaEHWGNiQ3ZnxJZW2c1KUzswzAeiHRtJq2ayPHbu0yaD0+r4DGF4ZEF8PsndG9cTFpTNaKb+nRqgIHviM0RBmnaNamFtArWbmXfqhqnWtmlinXioIw5M6Bw4GQS1Jj5t/fPks+GgkqUR6JjKrh7N4iK/mumZ71LMuccxdEIN4027khTYkCSyPy5545969ieRIiROF8oW30ef4QwPHPEl1n0Q0mot8fjLphC0WKdYG63ZIn8tImu0TFYVMAtDNxOIDsc24p85ctrhV/ihvUyOzwpcRWS7Grd8Y/mNQWL0+7M0UWvj50oprIWPIagRkLthazNPauZFt4G95O6nEbcn2Hp5W3Sa2Q8mSFE5OfopK4KKHL+YJa7wpiOmbQFTu63/LYdTKWLkxHipJqEHxVWl671g+2tWpVk+r0b/AEswnt2qNgi8ISSmryQxm2tqEP17aukvspMHaUXF8P9mb36z2Voy3bhx1r0w6LnqZdO0soENS2ScnDiVgcku2p5uf9hk8LLqNm9eNMTcOW79aNJdYznI1aXohRkvSLHft4vNCJTt1Z1qFtU1LejlE7mqgqCr+xPhAxnhk/27W5o5AU3fAxqK8qoHrec0pYLN5c1bWgAHz4BuLquNaReVreJgoVU/U4sWJEWVSzQ81V01a7m9hsMPtoj71Y7QBiVo1sz4/fe9bqxmP1tAiFxw5TNsx+U/jjtlKq7cbHmG6rHvjZSiopWeYLxhqLSGaxM+15nubRmjrWvDOlCFc2Nv4RlfffVEWHtLK26bErDs3SDL4H2vPbWJXLA1dEPtwivBg0j180dXlD/t3E4m+vq+Fdu7mtnvtruhquL7t914xfXvqw0eD5qbeAUB06Lsj+ZcPmJl6FTXsdmmTn2S8xM49MqCPZP/4YroJvYvS+vx297/xNCDHupx5NvRDHWYoAD/Gpt0Ngng8fhdW/TiRKzM0tGnHV/fbP9nR50+DVsnB5NQYf/AYduZx9s7neXJvvOMzDfrMMuHVT6WW48c1nX9WbU/eu/6wsN/9RaMegbQNRGIAD3rs1mzEEQuni85DzcQ8UboqlQAU36AKNvAQdFKROPU5OISItCJ8mQReZjB6qwRhCnMGGjqWg2EuhS4aWli5poVOXdmov+8HB/44b/vfdF7JdMUCwO57sox7yrIR3jlftaw9RghwOjJD+NrY1NCEO9yzRpsjump4Tzof48PKrmK8pdxjiBy4iCHOECQGHO6hDXWKbE6AYX23d2nR3cLvj2ND3Duw/aaeIV/aB9VqODaxzPOwOPOrMPg9dz2EeHyCMEOUcgTcbtA+BUqu9MfxSK44xZx4C/swBLxEM3f2cyxPmMfchfkCpCwJg5jElkylT4wBkpES0JgBs2wULmXESvBcCtknCRA2sFt0RBiGvsai/XAlRCxGyugimgZCLwLtUWSFnozYhgQhPLfALmNqyM8f8bjRcjQfYoXRGi997B30LP1e7NoOdHQzHHCCBwkuSboALzEQhlUpYOl30AB6DhO9ZasHwIlzgwDK4yPwN83kc5mku8/vFU34x/vhJnNSTONfCMXGKrFubkE5m9CZt9dq+K0QsbpWJUpP6j1jvwuI2nVvi9jY3kZSZNkYfNc3r2JRTZPyJ0bnW2Tq8P/cOKdNksZZ+cl5vMZaMChAJ0GAligWlUBTiz2UoI2DR/qy9YErJVNl7QrePw71edyP9SPS1bjbAoJU3aXb6VMXr0v33kh5Vr14cRcsgPa/KalneRBpd/Kia+k1VNqapmvjsxm+5u7IEtp7q5aaaf/gWbs58XT7R5Wb5n0IzeGkbiuO4sL9gf8DYLrvsoLtsssKgtzlKQgZp30spJA2VIREe8UnUw2JfoaP2YIjCS5fhwRWUKSKIkAc/KBvbYQm9y/IuMqwsp4LXXVa/fC+f6+f8CTz1wauy41VLTMw4ihzqdGMnQIyNXzyLYy29Qq14zFZfqrS0g8qI2ddbJlIorZhHvjZ33GosHp8tq5ePZzmZV7vZrPl+dfm8d+r4O93dvzNXyPcc1UMB+nXu9c4vNjSvI3AlYiyAjw9bSreKgX4Tg/lFtbpg6X1S+WTtsdxlnGEOLEmF0jYCFgFkUKjLUDS/3ihCufrBYEApRameUaaIDGOAVEbf36M0Ol3jVGkUXgDE0LmuN5A+WHobG3WTKQZKi3Lp3akRdX7zbY21623DNIX+9LU2h7TdM6R27K0Y+RpCTtw79uOu3/CcruPN4kzVo4h6AoQQiAX4SNEFp1jHGBcG8Az23MNwqHwYPl8vLz5ScjdJdBfvJSEPCbEk7xsrK0fI2tcXVnMZtfJkmn+B+gW3WSYhW+WpiwuJFdIkwgUJMgMggbyT0okw4O0NgzEVGzV9tPTvkLvM7LPmLr4rtNve0OC83j7Rjf0D0l/XSOXPwdyg2bE1xFJ7cPsmbqK007FZcyBUVR1TauCICsEU7GFQgGFgwPEoaSswtELX6jrJdHJ/Ho78n5+vN0ckBIuOWySZjJLEdUNukfudOaxsy3x6N5F5Vs5DfFmoSyUpbWATiSA0gOlklMM0z6WU2XQqZQTz83Efk50nD2qcmNxEger2T9Z0Bv8pOJdXJ2IojN+/wp1LcaXehQ90IW58Mc5lhHibGSuT28eiqMTcFlGwnVofcGehHAdy2wvFR0FhXAhuIhQiF0XsKAjixkRFhSy6MTIgLkQwcrJMOOfj+y3znfWrXBEk79KQuV/GnTMDEUo5zVb6C/FqsBIF0ZuV3mqw0fZr7WHU3Pn20uKDYNa+7VK0GPuhP8aAkSD0U+8ZYrI1wZKmlDVO7dVGG6sscTvd7l77MdyzBK2w3S4NMWe5ZEC4hTAycH8K3l9e6EfzQum2MUqqG6+R0MqAVdAmRKSQzh9oo4ydam3mVk2L3oXxhG4sLjcfUSq0MW9PE+gdOZi2mLaJZITVWUbT1oHDbKmiGEAdL6ziOB4+avdXveEArUa1Sj/IVpZePh/EYZtWd3bikIWo0iOspETcZ6kEwmRp7gmZoi9fCluW1pQgxC/Oy/B7WNbHnapTKPfsRMCNLkszrQIlYb+mvhTEfmOm0VDKzeaUuJoyBSAJosTvHZgVF7U6e9vqeTGbKz1rttC5S3++38HPpLbWQEbo4w8UJdxaFokyTeux5+UtIhQrBG+NFrD/sJc898N+P/Zq8cCvHep7OCCI+JTxn28wplcjFzfaD0IA6gxCoYUp35eFGOGcKSN+/SqNKIVVDivB0l+is3TMGmV//5SVinWvjB5xQ3edP3oyUOvGclNe4Qq4MO5Wqbk1EmoF5qSMmsq5bIq5M8fodTXdu6sdhl+v96EPp24QIBJzVpvUuVaCswxEP5PVftQNUy5cgcILWZbciZJOPMnHpxMSeb7vhd3cy+IKI1kYc58w/+nTM02HV0pnEE6GFevGl4SLVjmhihvr3JnZEhuSSt6apDfvKqFgrTi2vAiu7dy1ATh04NJhEKTkibJzUBaeWUypTou4DtWjyyHl7gTKESjs+uIBxbVWG6/GzOcxUHKKcIRCkFSi8l6A5ZSDZN5y1kXpKBsPPM45cY0WkofdO4l3N44bZJzkeZ4Bo8/8hGyucEZwKrFDs3vhW5qylMgySJtrJ+2UrYtbRMp7CIuR3ZxaAcLMFMWtCXszpoRoHOYoeJ1f1fv3XxbR1VLW3r3otroAioExYl5M6pSUGmq79qzAvrVTCDCi8a0UpDKd7S4WozGQ/3SG6FmSOUaqg5j3CaU+1Bb3DIeTpTfdxpMc30ouR9/Wqg7botOjC9jzcOJ5YWc8TmY5u5UkXm1jx5YDgXM+RC2nANULOkkZYyXNgX77HFipFBA0OFmBeliW2vFstWZso0FiT8pJ8/ih0L8Ileep7B1qbqCHseUTlo/waJgDaxHTX9w3brVHdRZvOxf12OYJBISzSmeQ0vCq2XqoUV2+4wMDxGg6AY7qlXAXTRFHPvW9ysdNn2XJZj/7snr5+cpq5jiSpH+w2okWkmwzy8c4aGCMs8S7leT+2nJzbXct8IJxnCZLl2pBF9GQXvQiChQxvv6vgusLjZyIwwXfffRNEKSP2nuwCgeWvhxaQ5YR0k4yt5pMun1YVJadLGsDNpkN6rWLRDbBzR+s/xayuGXZoxTaGtkYPNQkHD54sHqn5cp5x62iXk9FFxEcB0IgEPJ9v+/3fRPCTIDGiiZJFjHGQltU7me3O4zNbXqSdqpM/bb9JY0lTpGMWpd+/bXQc9Uxs2e9vbXl1Gt1dq/11ef1dq3dbleI6HDjdSDXa4LCVkfUavWGAlbOzd6sd9c7XN3stddhrcYeI3C6C8ozUG1/4IpcKDvpILC50+OlCwlCkb1uXf3rGpmzI4czdZMzBa7HWXinzyH91hff9RGVAexxIFV3Bl3FdLsSbbZyl5eOapWQZ8wl4bV1SWHodz/IWZdVbx+2uQ/G/XmBpWSn12GO7imCOF4XX5PPyNrO+jrbqrHefvfP++/cr9bGprI77n249vCjK1yn+mH7z+qhsjnPZL3/drsqffQHK2uDXmG//KsJ1arBbS9aPRU5lDOpG5gN1+XWgyhw0snory9dO1DTwennpxNnLtrDSJ7pJjBlXcfkblmkluUQmYbnXnkws1rm52WO5zDPt0xNFqSWYimovvGSyAsirx7xzaOuUm3XO+H0tvHAg74SnAhKW1HqgtI75Nrv8+3d7jrGld/71ferjz+g9u4r7Wq115H61drWh7Ecqut15b4kK/XO+ANp3BHrXI1jJWj3NvpwfNhWqmVBCbae3FzmF9QydcyJOeDuyo7A1ufraZIG9xLbdAZMJzEtnLnLBxd1mdDIdomlWyTiZUBNIMtyv7/2JJBkBDRZFAYh7/I/HdUFPuz0xsKJDFpua9Dl+5s7LCSlzuG40172/QXKDWpRq32oCPXGjqrQ861DwQ16W2+6Th2vNOaFcU8ZM+uz3FNqHdcTmS2Udl2oW4AVoIYoL9ChzHfbbXVtQ9hVXt61BorY6n/xmQgG2t4Om1YinacDE1OuiBJ7NkiiID0N7MBMgv7cdz8MbVu3CUGICYN1lRER1YEMbr7+r+/KBhJ5QFvQ5XnZUbeZHLuK4vJKrSWO6/Ue+IUfj69XpmPro/rq6rOLrimIZi4cXb/+6vm1c6LColVSFOl/DA314MfNrjkQ+M6YTVkrT4SKLElvC6JWi0UTh7HQls295VYrjmVxF1N8xEsSN+DMPUAtLY4lEV3CCGPBlGOWTDoeJOxjIg5Sx3FJgJOonsyd6bq+T4bPDKOIENZuhaqrKlIRBphS0wBUlOQBV7P6GyqaRIPW0UAUhJa488K5vltr3cBeR6gsvjw9vN258otMxUiTFMFjINVvPslEioDH55rUtCj9kWfzhiKKvNgtUbiwsecj2IJvAwQB3zBCcDSNJV8tQcTHJcD8qkmMyKYJpFSCvBZrGhU5AlRXrok3ujEV1QAvFWdGioijnwZRYgYfzkWzVCfq6PL3NkkI0QsCKhdfwcXMNGWJWAS5nDzid52lg+UFKrh1TnFWkczRazcvoS6Mp3Y/jxsNj70h1gTRVcCN7g02PC9TcyjIWoUXNWSVLAiscPvIy6exJvBeCcb451PwBhBkWOI1HxmkKPFZDn6CoNJohte8vSceL1FL5mwOSfu52KLTloU4Sqhcz7vT7IZY4QkeFn+/Z0e6HbEkINFpEszZyI7OEnJRZ37S5WiIU0KWVB3pkTxIOJ4gDm1xbXr31rG8qwxMkQoR5gccN1JFWrr+W/X6DbGXd/Ju3KWSeSQwuLE3jT1PqNVkf2cDrS0+VTappyEQZi0Nxpq3w85arjUzCGDDYNgtbPhwozEVvX5/ni3QOj+tPN0YYQQsxEuiyFoeUc2CIsNPeLOUr+yUBE9eOp4VP870KAlse8JxabB1ZW4SpJc/jWzCGNpn9tnBkhV9yxHdWCtsGuGrBxc2TQe75ikwTU7mebWiNRg/C9GuZHmemMX5NBdzbapJGuLLDz++PRWnWR5Pp3ILyIJHywbhW9CDfkPGCB55R9lAg9NVDzZLKPOHBipBuPj0UznKs1Kmk0dG2H82y/755lcQYgsxvs0mOxC1BAvJoZNneT48ARR0+3/rRLfTKIpYqulOEAR47l7i3Dt2gjRhYiX7+pd3iK3LuXM8fBoTZ3L8+6VFHOmENRZT5f8Q4FoBtVSjv5dNY0bEy2Mtg3HmASRr9Fy//Gyc56vz86/G8G2ILWAwONCCOfCNSrjwrFqyVktQ00oZG82s6VdKy7l2UbehV9nZLq1WHnxsCa/CZuaHFjKsAiyxVSNYU1F5FPqQ6CNUQjzEnkU2+/sE2aM9wuJrdCkdFbOEzCWRfuLYqW2naWQnepGmXGqo4t1btulGZHLz7sAw9UJ3bY7KhWnJJjZHKvKX+0vadBqSnPeYFLzh+yCE3P5bn8A8Lz9p7D2UTzVclCy1XwGqgVXf3zGebzy/Z1QmWehtl4A39bxwyQ9DMwzVSQjLC+UVWAx37r34cebBnIRnFO2TVba/7FELqwRhxBOCMSUZs/UIZi/cSvVZNLppF/bVTy/tpbbjTObSK1ec5HQySdKkSKIT3Q6Sy8NnQMoxekk0i8jMvvrchcgsdM4HIpCE1YULTxOkf9vPc8/zch6p8Pwa0nmAMdZxplXw5oWDZ57MyhD7TQvrFgiN+QfmN2xj7aCxFkJYXg7zrNnMKuESrsDtclYqQcsy1C8T4IdGqlsazIyVPoFEtV45vjO7rKqqBQApdDLUkYp0Uz0dkHvpjOXwd6z+9vFwOGO9Ngnm9DuTJAgmk0makH/vJcG/SXT28U8osZmH2CWbI9HFswv7eGSbDpIpr44K46AAgMh5nlVefnUKyVLjhb5OES4BQPM8LIV3Xr9jhANwfrGxg5vIgMsbfmVVLamzn5EKrH8QZC3nZZWsSFUPwrBpwX7D9ytZVjZUXLE2QO79rn9fNHy0N/r00/M6I8KA2zqxi81RQTYvD2c2QhG5eBYVySQtrv11EtjO6eQ/S6XNZUrl9NoAAAAASUVORK5CYII=\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Rainfall card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"mm\",\"decimals\":1,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/rainfall_chart_card.json b/application/src/main/data/json/system/widget_types/rainfall_chart_card.json new file mode 100644 index 0000000000..3a19b6e833 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/rainfall_chart_card.json @@ -0,0 +1,32 @@ +{ + "fqn": "rainfall_chart_card", + "name": "Rainfall chart card", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a rainfall data as a combination of the latest and aggregated values. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'rainfall', label: 'Rainfall', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'mm', decimals: 1 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'rainfall', 'mm', 1);\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 2 - 1;\\nif (value < -3) {\\n\\tvalue = -3;\\n} else if (value > 3) {\\n\\tvalue = 3;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Rainfall\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:weather-pouring\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/rainfall_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/rainfall_chart_card_with_background.json new file mode 100644 index 0000000000..75543ca962 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/rainfall_chart_card_with_background.json @@ -0,0 +1,32 @@ +{ + "fqn": "rainfall_chart_card_with_background", + "name": "Rainfall chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays a rainfall data as a combination of the latest and aggregated values with background. Optionally may display the corresponding historical values as a simplified chart.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 3.5, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onLatestDataUpdated();\n}\n\nself.onResize = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onResize();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.aggregatedValueCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '400px',\n previewHeight: '300px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'rainfall', label: 'Rainfall', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)', units: 'mm', decimals: 1 }\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent, configData) {\n return configComponent.createDefaultAggregatedValueLatestDataKeys(configData, 'rainfall', 'mm', 1);\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-aggregated-value-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "tb-aggregated-value-card-key-settings", + "hasBasicMode": true, + "basicModeDirective": "tb-aggregated-value-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"Main building\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{\"showLines\":true,\"fillLines\":true,\"showPoints\":false},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"#4caf50\",\"settings\":{\"position\":\"center\",\"font\":{\"size\":52,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"1\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.9408410830697858,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta percent\",\"color\":\"#f44336\",\"settings\":{\"position\":\"rightTop\",\"font\":{\"size\":14,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"20px\"},\"color\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[{\"from\":null,\"to\":0,\"color\":\"#198038\"},{\"from\":0,\"to\":0,\"color\":\"rgba(0, 0, 0, 0.87)\"},{\"from\":0,\"to\":null,\"color\":\"#D12730\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":true},\"_hash\":0.06392321853157967,\"funcBody\":\"var value = prevValue + Math.random() * 6 - 3;\\nvar multiplier = Math.pow(10, 2 || 0);\\nvar value = Math.round(value * multiplier) / multiplier;\\nif (value < -25) {\\n\\tvalue = -25;\\n} else if (value > 25) {\\n\\tvalue = 25;\\n} \\nreturn value;\",\"aggregationType\":null,\"units\":\"%\",\"decimals\":0,\"usePostProcessing\":null,\"postFuncBody\":null},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Delta absolute\",\"color\":\"#607d8b\",\"settings\":{\"position\":\"rightBottom\",\"font\":{\"size\":11,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"rangeList\":[],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showArrow\":false},\"_hash\":0.44695098620509865,\"funcBody\":\"var value = prevValue + Math.random() * 2 - 1;\\nif (value < -3) {\\n\\tvalue = -3;\\n} else if (value > 3) {\\n\\tvalue = 3;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":\"mm\",\"decimals\":1,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1691927717318,\"endTimeMs\":1692014117318},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"stack\":false,\"fontSize\":10,\"fontColor\":\"#545454\",\"showTooltip\":true,\"tooltipIndividual\":false,\"tooltipCumulative\":false,\"hideZeros\":false,\"grid\":{\"verticalLines\":true,\"horizontalLines\":true,\"outlineWidth\":1,\"color\":\"#545454\",\"backgroundColor\":null,\"tickColor\":\"#DDDDDD\"},\"xaxis\":{\"title\":null,\"showLabels\":true,\"color\":\"#545454\"},\"yaxis\":{\"min\":null,\"max\":null,\"title\":null,\"showLabels\":true,\"color\":\"#545454\",\"tickSize\":null,\"tickDecimals\":0,\"ticksFormatter\":\"\"},\"shadowSize\":4,\"smoothLines\":false,\"comparisonEnabled\":false,\"xaxisSecond\":{\"axisPosition\":\"top\",\"title\":null,\"showLabels\":true},\"showLegend\":true,\"legendConfig\":{\"direction\":\"column\",\"position\":\"bottom\",\"sortDataKeys\":false,\"showMin\":false,\"showMax\":false,\"showAvg\":true,\"showTotal\":false,\"showLatest\":false},\"customLegendEnabled\":false,\"showSubtitle\":true,\"subtitle\":\"${entityName}\",\"subtitleFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"subtitleColor\":\"rgba(0, 0, 0, 0.38)\",\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"400\",\"lineHeight\":\"16px\"},\"dateColor\":\"rgba(0, 0, 0, 0.38)\",\"showChart\":true,\"chartColor\":\"rgba(0, 0, 0, 0.87)\",\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Rainfall\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:weather-pouring\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"24px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":false,\"displayTimewindow\":true,\"decimals\":0,\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"24px\",\"icon\":null,\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":false},\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card.json b/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card.json new file mode 100644 index 0000000000..2fcc6ca760 --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card.json @@ -0,0 +1,32 @@ +{ + "fqn": "simple_rainfall_chart_card", + "name": "Simple rainfall chart card", + "deprecated": false, + "image": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAMgAAACgCAMAAAB+IdObAAAAgVBMVEUAAADg4ODf39/g4ODg4OD////g4OAjTMchISHj4+M9PT3x8fGsrKxYWFiQkJDI0vHHx8d1j9zj6PitvOp0dHQvLy9aeNWRpeM8PDyCgoKenp7V1dXy9Ps+Ys5mZmYwV8u6urpKSkrW3fXk6fifsedLS0tohNm6x+0xV8qDm99MbtG6RkKAAAAABXRSTlMA7yC/r1EOHTEAAAQeSURBVHja7M9JAcAgDAAwytEP/v0OGdAlDtIAAAAAAAB+p4/I181+HrHX83b0Ngs8zmS0XCVElUiKXEbkNh+79bJaIQxFYXi0YN8S9iABY0B0cN7/FVsF5VApdNZtm3+U6Ogj5DIg0RqQaA1ItAYkWv8AwoqfxYjQdxDfiAq/zXPOds156ddQyIAjySgJv9H3EK6mXF64yrUsk5wSTZepVUZYCC/V8FlyXBABtDbAbQXUFMZuDE/VdP/IASEsbcWeSeE3CGpGq2VKYHKQbJNoniip0fI5jAdZt1NkSzoh1eZUGdlhpAckw6mjCGAGJosHsQ3onVcYmE4IpY060BepxAdk/+sHhNtLIkJ0akjzvHhF3k6IHFtEpandIOnFIVcEbKh9p2B+3yN5F2S0G0QKLCQE8AnUk+HLqZXQiBbyL5CZKNEcEqLuE1xxTxn39Pdv9xNyay54VP/g0fiwBiRaAxKtAYnWgERrQKI1INGKDNHu/Q9ANFcikqwPh7BQW30tJPxoiMrUsec1PRrywZ657bgKQmH4aoUFiudjRZ3a03Te/wE3MILd7phx146pid9F8wterC8slNgDUpuCLYswbmPKNyxSoWuzh852RVRnGSh6mxOhpvwLhwHONyZySBFZoIXw8DiOwaZEPOTuocBKxgQpDDjovbWI45al64CBskYNFph4fFQ5T39FJPI7eAEVwzRFVo32N03k4AH+4gODp0X8e+sDhMQAhnMrr+oclkJZEQAEhf0vlSXTa1cw5ykRkWey2keRGnpyQtqsJuQMCyn7BUhL0LgYwCQBMqqEPM5Y484XIRofDCEJ+3QiKp6+yKeAZVy46X/Hvsqn+SiQJzyVP41MdK5IG/q+FrHVR6axvmNsRkQkIIpvkUx+7H+PRCBuOndqYgL7gA2w1Av0wzagLmfHUt/jFqk3t7UAHkVCcjXRz3MAPduZqTuRnLtaNWCkHeNW5kxkhEy3oIuVfeqysmTowWyoOtvP3uyDyKm1cVCrTSBteFUObZjJ6rUIyUKp9akmJlswKQYnjikP4H9wi+YJkdhUbekIia1IpG+uhb4QSiQHEK1eM9/eOIY1sATHeUKkHhdzqklml0YnXbzeOWb7XPWE0L01fbpdznwRXdnYo45+Ehkmpk63q4tkJIRHxJfyWCjCj7C2iD9ekCtpI1goQrFcWcRWZLmTtoOFIs6loGuLnOxzpwtvAJCr6yUi2gM/YG0R+8YAeSxRw4bsaRHKUhdgZRFR2+dnTrKXiFT9F6sVRCYQ8Arc9N/9scWP2B4ee49ti3iYOH3ctkjj2bhtEcsusotshV3k3dhF3o1d5N3YRd6NXeRPO3dCAAAIAjAQP/pHtgbiXYMVWDVCqskYp4WM1WO5s/tMkGLufN1YMwAAAAAAAH5zAZS0p15sQX4JAAAAAElFTkSuQmCC", + "description": "Displays historical rainfall values as a simplified chart. Optionally may display the corresponding latest rainfall value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'rainfall', label: 'Rainfall', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'rainfall', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#7191EF\"},{\"from\":0,\"to\":2.5,\"color\":\"#4B70DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#305AD7\"},{\"from\":7.6,\"to\":null,\"color\":\"#234CC7\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Rainfall\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:weather-pouring\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":1,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"mm\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card_with_background.json b/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card_with_background.json new file mode 100644 index 0000000000..9b3d56233b --- /dev/null +++ b/application/src/main/data/json/system/widget_types/simple_rainfall_chart_card_with_background.json @@ -0,0 +1,32 @@ +{ + "fqn": "simple_rainfall_chart_card_with_background", + "name": "Simple rainfall chart card with background", + "deprecated": false, + "image": "data:image/png;base64,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", + "description": "Displays historical rainfall values as a simplified chart with background. Optionally may display the corresponding latest rainfall value.", + "descriptor": { + "type": "timeseries", + "sizeX": 4.5, + "sizeY": 2, + "resources": [], + "templateHtml": "\n\n", + "templateCss": ".legend {\n font-size: 13px;\n line-height: 10px;\n}\n\n.legend table { \n border-spacing: 0px;\n border-collapse: separate;\n}\n\n.mouse-events .flot-overlay {\n cursor: crosshair; \n}\n\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueChartCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onDataUpdated();\n};\n\nself.onLatestDataUpdated = function() {\n self.ctx.$scope.valueChartCardWidget.onLatestDataUpdated();\n}\n\nself.onEditModeChanged = function() {\n self.ctx.$scope.valueChartCardWidget.onEditModeChanged();\n}\n\nself.onDestroy = function() {\n self.ctx.$scope.valueChartCardWidget.onDestroy();\n}\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n previewWidth: '300px',\n previewHeight: '150px',\n embedTitlePanel: true,\n hasAdditionalLatestDataKeys: true,\n defaultDataKeysFunction: function() {\n return [\n { name: 'rainfall', label: 'Rainfall', type: 'timeseries', color: 'rgba(0, 0, 0, 0.87)'}\n ];\n },\n defaultLatestDataKeysFunction: function(configComponent) {\n return [{ name: 'rainfall', label: 'Latest', type: 'timeseries'}];\n }\n };\n}\n", + "settingsSchema": "{}", + "dataKeySettingsSchema": "{}", + "latestDataKeySettingsSchema": "{}", + "settingsDirective": "tb-value-chart-card-widget-settings", + "dataKeySettingsDirective": "", + "latestDataKeySettingsDirective": "", + "hasBasicMode": true, + "basicModeDirective": "tb-value-chart-card-basic-config", + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Rainfall\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]},\"latestDataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Latest\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"settings\":{},\"_hash\":0.8587686344902596,\"funcBody\":\"var value = prevValue + Math.random() * 4 - 2;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 8) {\\n\\tvalue = 8;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}]}],\"showTitle\":true,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":null,\"padding\":\"0\",\"settings\":{\"layout\":\"left\",\"autoScale\":true,\"showValue\":true,\"valueFont\":{\"family\":\"Roboto\",\"size\":28,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\",\"lineHeight\":\"32px\"},\"valueColor\":{\"type\":\"range\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"rangeList\":[{\"from\":0,\"to\":0,\"color\":\"#6083EC\"},{\"from\":0,\"to\":2.5,\"color\":\"#4369DD\"},{\"from\":2.5,\"to\":7.6,\"color\":\"#2B54CE\"},{\"from\":7.6,\"to\":null,\"color\":\"#224AC2\"}],\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"image\",\"imageBase64\":\"data:image/png;base64,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\",\"imageUrl\":null,\"color\":\"#fff\",\"overlay\":{\"enabled\":true,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Rainfall\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":null,\"mobileHeight\":null,\"configMode\":\"basic\",\"actions\":{},\"showTitleIcon\":true,\"titleIcon\":\"mdi:weather-pouring\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"titleFont\":{\"size\":16,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\",\"lineHeight\":\"24px\"},\"iconSize\":\"18px\",\"titleTooltip\":\"\",\"widgetStyle\":{},\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"useDashboardTimewindow\":true,\"decimals\":1,\"titleColor\":\"rgba(0, 0, 0, 0.87)\",\"borderRadius\":null,\"units\":\"mm\",\"displayTimewindow\":true,\"timewindow\":{\"hideInterval\":false,\"hideLastInterval\":false,\"hideQuickInterval\":false,\"hideAggregation\":false,\"hideAggInterval\":false,\"hideTimezone\":false,\"selectedTab\":1,\"history\":{\"historyType\":2,\"timewindowMs\":60000,\"interval\":43200000,\"fixedTimewindow\":{\"startTimeMs\":1697382151041,\"endTimeMs\":1697468551041},\"quickInterval\":\"CURRENT_MONTH_SO_FAR\"},\"aggregation\":{\"type\":\"AVG\",\"limit\":25000}},\"timewindowStyle\":{\"showIcon\":false,\"iconSize\":\"24px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"400\",\"style\":\"normal\",\"lineHeight\":\"16px\"},\"color\":\"rgba(0, 0, 0, 0.38)\",\"displayTypePrefix\":true}}" + }, + "externalId": null, + "tags": [ + "weather", + "environment", + "rain", + "rainfall" + ] +} \ No newline at end of file From 6d7cb95492c1a90fc55dab13a5f3d95a563bf690 Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Fri, 20 Oct 2023 15:46:53 +0300 Subject: [PATCH 233/267] Bigger timeout in tests for msg processing --- .../queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java index 20b765da6d..38582d0fce 100644 --- a/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java +++ b/application/src/test/java/org/thingsboard/server/service/queue/ruleengine/TbRuleEngineQueueConsumerManagerTest.java @@ -184,7 +184,7 @@ public class TbRuleEngineQueueConsumerManagerTest { ruleEngineConsumerContext.stop(); if (generateQueueMsgs) { - await().atMost(2, TimeUnit.SECONDS) + await().atMost(10, TimeUnit.SECONDS) .untilAsserted(() -> { log.debug("totalConsumedMsgs = {}, totalProcessedMsgs = {}", totalConsumedMsgs.get(), totalProcessedMsgs.get()); assertThat(totalProcessedMsgs.get()).isEqualTo(totalConsumedMsgs.get()); From 66d4f010e86ab781304ba76c4aa8da91168d4ab5 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 20 Oct 2023 16:15:58 +0300 Subject: [PATCH 234/267] UI: Improve some widgets style. --- .../aggregated-value-card-widget.component.ts | 8 ++++---- .../lib/cards/aggregated-value-card.models.ts | 2 +- .../cards/progress-bar-widget.component.ts | 4 ++-- .../lib/cards/value-card-widget.component.ts | 10 +++++----- .../value-chart-card-widget.component.ts | 6 +++--- .../lib/count/count-widget.component.ts | 4 ++-- .../battery-level-widget.component.ts | 2 +- .../signal-strength-widget.component.ts | 6 +++--- .../home/models/dashboard-component.models.ts | 2 +- .../shared/models/widget-settings.models.ts | 20 +++++++++++++------ 10 files changed, 36 insertions(+), 28 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts index b5b37df7f8..86046df6d7 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card-widget.component.ts @@ -48,7 +48,7 @@ import { import { TbFlot } from '@home/components/widget/lib/flot-widget'; import { TbFlotKeySettings, TbFlotSettings } from '@home/components/widget/lib/flot-widget.models'; import { DataKey } from '@shared/models/widget.models'; -import { formatNumberValue, formatValue, isDefined } from '@core/utils'; +import { formatNumberValue, formatValue, isDefined, isDefinedAndNotNull, isNumeric } from '@core/utils'; import { map } from 'rxjs/operators'; import { ResizeObserver } from '@juggle/resize-observer'; @@ -119,7 +119,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit this.showSubtitle = this.settings.showSubtitle; const subtitle = this.settings.subtitle; this.subtitle$ = this.ctx.registerLabelPattern(subtitle, this.subtitle$); - this.subtitleStyle = textStyle(this.settings.subtitleFont, '0.25px'); + this.subtitleStyle = textStyle(this.settings.subtitleFont); this.subtitleColor = this.settings.subtitleColor; const dataKey = getDataKey(this.ctx.defaultSubscription.datasources); @@ -148,7 +148,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit this.showDate = this.settings.showDate; this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); - this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); + this.dateStyle = textStyle(this.settings.dateFont); this.dateColor = this.settings.dateColor; this.backgroundStyle = backgroundStyle(this.settings.background); @@ -230,7 +230,7 @@ export class AggregatedValueCardWidgetComponent implements OnInit, AfterViewInit const tsValue = getTsValueByLatestDataKey(this.ctx.latestData, aggValue.key); let ts; let value; - if (tsValue) { + if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { ts = tsValue[0]; value = tsValue[1]; aggValue.value = formatValue(value, (aggValue.key.decimals || this.ctx.decimals), null, false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts index b199aaa9c6..1d02d71cdf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/aggregated-value-card.models.ts @@ -92,7 +92,7 @@ export const computeAggregatedCardValue = key, value: '', units: key.units, - style: textStyle(settings.font, '0.25px'), + style: textStyle(settings.font), color: ColorProcessor.fromSettings(settings.color), center: position === AggregatedValueCardKeyPosition.center, showArrow: settings.showArrow, diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts index 2b9d4328d5..43d2c6300c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/progress-bar-widget.component.ts @@ -124,7 +124,7 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI this.layout = this.settings.layout; this.showValue = this.settings.showValue; - this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueStyle = textStyle(this.settings.valueFont); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.showTitleValueRow = this.showValue || @@ -140,7 +140,7 @@ export class ProgressBarWidgetComponent implements OnInit, OnDestroy, AfterViewI this.showTicks = this.settings.showTicks && this.layout === ProgressBarLayout.default; if (this.showTicks) { - this.ticksStyle = textStyle(this.settings.ticksFont, '0.1px'); + this.ticksStyle = textStyle(this.settings.ticksFont); this.ticksStyle.color = this.settings.ticksColor; } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts index 75a922daff..a80d1d850b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-card-widget.component.ts @@ -27,7 +27,7 @@ import { ViewChild } from '@angular/core'; import { WidgetContext } from '@home/models/widget-component.models'; -import { formatValue, isDefinedAndNotNull } from '@core/utils'; +import { formatValue, isDefinedAndNotNull, isNumeric } from '@core/utils'; import { backgroundStyle, ColorProcessor, @@ -132,14 +132,14 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro this.showLabel = this.settings.showLabel; const label = getLabel(this.ctx.datasources); this.label$ = this.ctx.registerLabelPattern(label, this.label$); - this.labelStyle = textStyle(this.settings.labelFont, '0.25px'); + this.labelStyle = textStyle(this.settings.labelFont); this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); - this.valueStyle = textStyle(this.settings.valueFont, '0.13px'); + this.valueStyle = textStyle(this.settings.valueFont); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.showDate = this.settings.showDate; this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); - this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); + this.dateStyle = textStyle(this.settings.dateFont); this.dateColor = ColorProcessor.fromSettings(this.settings.dateColor); this.backgroundStyle = backgroundStyle(this.settings.background); @@ -179,7 +179,7 @@ export class ValueCardWidgetComponent implements OnInit, AfterViewInit, OnDestro const tsValue = getSingleTsValue(this.ctx.data); let ts; let value; - if (tsValue) { + if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { ts = tsValue[0]; value = tsValue[1]; this.valueText = formatValue(value, this.decimals, this.units, false); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts index ce5b61943c..8b05847fb3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/cards/value-chart-card-widget.component.ts @@ -28,7 +28,7 @@ import { ViewEncapsulation } from '@angular/core'; import { WidgetContext } from '@home/models/widget-component.models'; -import { formatValue, isDefinedAndNotNull } from '@core/utils'; +import { formatValue, isDefinedAndNotNull, isNumeric } from '@core/utils'; import { backgroundStyle, ColorProcessor, @@ -126,7 +126,7 @@ export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnD this.layout = this.settings.layout; this.showValue = this.settings.showValue; - this.valueStyle = textStyle(this.settings.valueFont, '0.25px'); + this.valueStyle = textStyle(this.settings.valueFont); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.backgroundStyle = backgroundStyle(this.settings.background); @@ -192,7 +192,7 @@ export class ValueChartCardWidgetComponent implements OnInit, AfterViewInit, OnD if (this.showValue && this.valueKey) { const tsValue = getTsValueByLatestDataKey(this.ctx.latestData, this.valueKey); let value; - if (tsValue) { + if (tsValue && isDefinedAndNotNull(tsValue[1]) && isNumeric(tsValue[1])) { value = tsValue[1]; this.valueText = formatValue(value, this.decimals, this.units, false); } else { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts index 0f3c922e1b..3302ba4477 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/count/count-widget.component.ts @@ -115,7 +115,7 @@ export class CountWidgetComponent implements OnInit, AfterViewInit, OnDestroy { this.showLabel = this.settings.showLabel; this.label = this.settings.label; - this.labelStyle = textStyle(this.settings.labelFont, '0.4px'); + this.labelStyle = textStyle(this.settings.labelFont); this.labelColor = ColorProcessor.fromSettings(this.settings.labelColor); this.showIcon = this.settings.showIcon; @@ -136,7 +136,7 @@ export class CountWidgetComponent implements OnInit, AfterViewInit, OnDestroy { }; this.iconBackgroundColor = ColorProcessor.fromSettings(this.settings.iconBackgroundColor); - this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueStyle = textStyle(this.settings.valueFont); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.showChevron = this.settings.showChevron; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts index a983dc81a9..31f98aff6c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/battery-level-widget.component.ts @@ -183,7 +183,7 @@ export class BatteryLevelWidgetComponent implements OnInit, OnDestroy, AfterView this.showValue = this.settings.showValue; this.autoScaleValueSize = this.showValue && this.settings.autoScaleValueSize; - this.valueStyle = textStyle(this.settings.valueFont, '0.1px'); + this.valueStyle = textStyle(this.settings.valueFont); this.valueColor = ColorProcessor.fromSettings(this.settings.valueColor); this.batteryLevelColor = ColorProcessor.fromSettings(this.settings.batteryLevelColor); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts index 10ba3b3b1b..8427cf362b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/indicator/signal-strength-widget.component.ts @@ -142,7 +142,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi this.showDate = this.settings.showDate; if (this.showDate) { this.dateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, this.settings.dateFormat); - this.dateStyle = textStyle(this.settings.dateFont, '0.25px'); + this.dateStyle = textStyle(this.settings.dateFont); this.dateStyle.color = this.settings.dateColor; } @@ -173,7 +173,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi if (dataKey?.units) { this.units = dataKey.units; } - this.tooltipValueStyle = textStyle(this.settings.tooltipValueFont, '0.13px'); + this.tooltipValueStyle = textStyle(this.settings.tooltipValueFont); this.tooltipValueStyle.color = this.settings.tooltipValueColor; this.tooltipValueLabelStyle = {...this.tooltipValueStyle, ...this.tooltipValueLabelStyle}; } @@ -181,7 +181,7 @@ export class SignalStrengthWidgetComponent implements OnInit, OnDestroy, AfterVi if (this.showTooltipDate) { this.tooltipDateFormat = DateFormatProcessor.fromSettings(this.ctx.$injector, {...this.settings.tooltipDateFormat, ...{hideLastUpdatePrefix: true}}); - this.tooltipDateStyle = textStyle(this.settings.tooltipDateFont, '0.13px'); + this.tooltipDateStyle = textStyle(this.settings.tooltipDateFont); this.tooltipDateStyle.color = this.settings.tooltipDateColor; this.tooltipDateLabelStyle = {...this.tooltipDateStyle, ...this.tooltipDateLabelStyle}; } diff --git a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts index 8104e80e36..fbfa520fb3 100644 --- a/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/dashboard-component.models.ts @@ -437,7 +437,7 @@ export class DashboardWidget implements GridsterItem, IDashboardWidget { && this.widgetContext.widgetTitleTooltip.length ? this.widgetContext.widgetTitleTooltip : this.widget.config.titleTooltip; this.titleTooltip = this.dashboard.utils.customTranslation(this.titleTooltip, this.titleTooltip); this.showTitle = isDefined(this.widget.config.showTitle) ? this.widget.config.showTitle : true; - this.titleStyle = {...(this.widget.config.titleStyle || {}), ...textStyle(this.widget.config.titleFont, 'normal')}; + this.titleStyle = {...(this.widget.config.titleStyle || {}), ...textStyle(this.widget.config.titleFont)}; if (this.widget.config.titleColor) { this.titleStyle.color = this.widget.config.titleColor; } diff --git a/ui-ngx/src/app/shared/models/widget-settings.models.ts b/ui-ngx/src/app/shared/models/widget-settings.models.ts index 5055893b6f..bd10859e55 100644 --- a/ui-ngx/src/app/shared/models/widget-settings.models.ts +++ b/ui-ngx/src/app/shared/models/widget-settings.models.ts @@ -302,7 +302,11 @@ export class SimpleDateFormatProcessor extends DateFormatProcessor { } update(ts: string| number | Date): void { - this.formatted = this.datePipe.transform(ts, this.settings.format); + if (ts) { + this.formatted = this.datePipe.transform(ts, this.settings.format); + } else { + this.formatted = ' '; + } } } @@ -320,12 +324,16 @@ export class LastUpdateAgoDateFormatProcessor extends DateFormatProcessor { } update(ts: string| number | Date): void { - const agoText = this.dateAgoPipe.transform(ts, {applyAgo: true, short: true, textPart: true}); - if (this.settings.hideLastUpdatePrefix) { - this.formatted = agoText; + if (ts) { + const agoText = this.dateAgoPipe.transform(ts, {applyAgo: true, short: true, textPart: true}); + if (this.settings.hideLastUpdatePrefix) { + this.formatted = agoText; + } else { + this.formatted = this.translate.instant('date.last-update-n-ago-text', + {agoText}); + } } else { - this.formatted = this.translate.instant('date.last-update-n-ago-text', - {agoText}); + this.formatted = ' '; } } From e5dfd337528e09195a6f24a1769130032d39b3d7 Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Fri, 20 Oct 2023 17:01:13 +0300 Subject: [PATCH 235/267] UI: Horizontal cards layout settings improvements. --- .../system/widget_types/horizontal_humidity_card.json | 4 ++-- .../horizontal_humidity_card_with_background.json | 4 ++-- .../system/widget_types/horizontal_pressure_card.json | 4 ++-- .../horizontal_pressure_card_with_background.json | 4 ++-- .../system/widget_types/horizontal_rainfall_card.json | 4 ++-- .../horizontal_rainfall_card_with_background.json | 4 ++-- .../system/widget_types/horizontal_temperature_card.json | 4 ++-- .../horizontal_temperature_card_with_background.json | 4 ++-- .../json/system/widget_types/horizontal_value_card.json | 9 +++++---- .../system/widget_types/horizontal_wind_speed_card.json | 4 ++-- .../horizontal_wind_speed_card_with_background.json | 4 ++-- 11 files changed, 25 insertions(+), 24 deletions(-) diff --git a/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json b/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json index 105929125d..2b58b32288 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_humidity_card.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json index 14882ac7e6..8dc416249c 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/horizontal_humidity_card_with_background.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'humidity', label: 'Humidity', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json b/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json index c96757cebf..fbc79c2255 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_pressure_card.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json index 58d63484ae..d0beafbf6d 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/horizontal_pressure_card_with_background.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'pressure', label: 'Pressure', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json index 2e619546cb..4eefae88c8 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json index c8aa515031..62bad4bbb0 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/horizontal_rainfall_card_with_background.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'rainfall', label: 'Rainfall', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json b/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json index 153195a499..8884bcf132 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_temperature_card.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json index 1c711e7e1f..0bb6084afa 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/horizontal_temperature_card_with_background.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_value_card.json b/application/src/main/data/json/system/widget_types/horizontal_value_card.json index 50c50050bc..fd52ab74e4 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_value_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_value_card.json @@ -7,17 +7,18 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", "hasBasicMode": true, "basicModeDirective": "tb-value-card-basic-config", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"family\":\"Roboto\",\"size\":52,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}}},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Temperature\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.2392660816082064,\"funcBody\":\"var value = prevValue + Math.random() * 40 - 20;\\nif (value < -60) {\\n\\tvalue = -60;\\n} else if (value > 60) {\\n\\tvalue = 60;\\n}\\nreturn value;\",\"aggregationType\":null,\"units\":null,\"decimals\":null,\"usePostProcessing\":null,\"postFuncBody\":null}],\"alarmFilterConfig\":{\"statusList\":[\"ACTIVE\"]}}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":false,\"backgroundColor\":\"rgba(0, 0, 0, 0)\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"0px\",\"settings\":{\"labelPosition\":\"top\",\"layout\":\"horizontal\",\"showLabel\":true,\"labelFont\":{\"family\":\"Roboto\",\"size\":16,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"labelColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showIcon\":true,\"iconSize\":40,\"iconSizeUnit\":\"px\",\"icon\":\"thermostat\",\"iconColor\":{\"type\":\"constant\",\"color\":\"#5469FF\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"valueFont\":{\"size\":36,\"sizeUnit\":\"px\",\"family\":\"Roboto\",\"weight\":\"500\",\"style\":\"normal\"},\"valueColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"showDate\":true,\"dateFormat\":{\"format\":null,\"lastUpdateAgo\":true,\"custom\":false},\"dateFont\":{\"family\":\"Roboto\",\"size\":12,\"sizeUnit\":\"px\",\"style\":\"normal\",\"weight\":\"500\"},\"dateColor\":{\"type\":\"constant\",\"color\":\"rgba(0, 0, 0, 0.38)\",\"colorFunction\":\"var temperature = value;\\nif (typeof temperature !== undefined) {\\n var percent = (temperature + 60)/120 * 100;\\n return tinycolor.mix('blue', 'red', percent).toHexString();\\n}\\nreturn 'blue';\"},\"background\":{\"type\":\"color\",\"color\":\"#fff\",\"overlay\":{\"enabled\":false,\"color\":\"rgba(255,255,255,0.72)\",\"blur\":3}},\"autoScale\":true},\"title\":\"Horizontal value card\",\"dropShadow\":true,\"enableFullscreen\":false,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400},\"units\":\"°C\",\"decimals\":0,\"useDashboardTimewindow\":true,\"showLegend\":false,\"widgetStyle\":{},\"actions\":{},\"configMode\":\"basic\",\"displayTimewindow\":true,\"margin\":\"0px\",\"borderRadius\":\"0px\",\"widgetCss\":\"\",\"pageSize\":1024,\"noDataDisplayMessage\":\"\",\"showTitleIcon\":false,\"titleTooltip\":\"\",\"titleFont\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1.6\"},\"titleIcon\":\"\",\"iconColor\":\"rgba(0, 0, 0, 0.87)\",\"iconSize\":\"14px\",\"timewindowStyle\":{\"showIcon\":true,\"iconSize\":\"14px\",\"icon\":\"query_builder\",\"iconPosition\":\"left\",\"font\":{\"size\":12,\"sizeUnit\":\"px\",\"family\":null,\"weight\":null,\"style\":null,\"lineHeight\":\"1\"},\"color\":null}}" }, - "externalId": null + "externalId": null, + "tags": null } \ No newline at end of file diff --git a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json index 94e177672f..e31569ea97 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json +++ b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", diff --git a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json index 3b2c8cf8ff..3808c7d538 100644 --- a/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json +++ b/application/src/main/data/json/system/widget_types/horizontal_wind_speed_card_with_background.json @@ -7,11 +7,11 @@ "descriptor": { "type": "latest", "sizeX": 5, - "sizeY": 1.5, + "sizeY": 1, "resources": [], "templateHtml": "\n", "templateCss": "", - "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '130px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", + "controllerScript": "self.onInit = function() {\n self.ctx.$scope.valueCardWidget.onInit();\n};\n\nself.onDataUpdated = function() {\n self.ctx.$scope.valueCardWidget.onDataUpdated();\n};\n\nself.typeParameters = function() {\n return {\n maxDatasources: 1,\n maxDataKeys: 1,\n singleEntity: true,\n horizontal: true,\n previewWidth: '420px',\n previewHeight: '90px',\n embedTitlePanel: true,\n defaultDataKeysFunction: function() {\n return [{ name: 'speed', label: 'Wind Speed', type: 'timeseries' }];\n }\n };\n};\n\nself.onDestroy = function() {\n};\n", "settingsSchema": "", "dataKeySettingsSchema": "", "settingsDirective": "tb-value-card-widget-settings", From deb8cf3a22f2792bb824d531b5d427007c1afb83 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 20 Oct 2023 17:43:21 +0300 Subject: [PATCH 236/267] UI: Add support inside widget bundle added new widgets --- ui-ngx/src/app/core/http/widget.service.ts | 9 ++++ .../import-export/import-export.service.ts | 6 +-- .../pages/widget/widget-editor.component.ts | 19 +++++-- .../widgets-bundle-widgets.component.html | 26 ++++++--- .../widgets-bundle-widgets.component.ts | 54 ++++++++++++++++--- .../assets/locale/locale.constant-en_US.json | 2 + ui-ngx/src/typings/utils.d.ts | 6 +++ 7 files changed, 101 insertions(+), 21 deletions(-) diff --git a/ui-ngx/src/app/core/http/widget.service.ts b/ui-ngx/src/app/core/http/widget.service.ts index 9dcda4ef8a..6b53e4d0cb 100644 --- a/ui-ngx/src/app/core/http/widget.service.ts +++ b/ui-ngx/src/app/core/http/widget.service.ts @@ -236,6 +236,15 @@ export class WidgetService { return this.http.get>(url, defaultHttpOptionsFromConfig(config)); } + public addWidgetFqnToWidgetBundle(widgetsBundleId: string, fqn: string, config?: RequestConfig) { + return this.getBundleWidgetTypeFqns(widgetsBundleId, config).pipe( + mergeMap(widgetsBundleFqn => { + widgetsBundleFqn.push(fqn); + return this.updateWidgetsBundleWidgetFqns(widgetsBundleId, widgetsBundleFqn, config); + }) + ); + } + public getWidgetTemplate(widgetTypeParam: widgetType, config?: RequestConfig): Observable { const templateWidgetType = widgetTypesData.get(widgetTypeParam); 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 e91375e75e..e71c4df0d5 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 @@ -297,7 +297,7 @@ export class ImportExportService { ); } - public importWidgetType(): Observable { + public importWidgetType(): Observable { return this.openImportDialog('widget-type.import', 'widget-type.widget-type-file').pipe( mergeMap((widgetTypeDetails: WidgetTypeDetails) => { if (!this.validateImportedWidgetTypeDetails(widgetTypeDetails)) { @@ -309,9 +309,7 @@ export class ImportExportService { return this.widgetService.saveImportedWidgetTypeDetails(widgetTypeDetails); } }), - catchError((err) => { - return of(null); - }) + catchError(() => of(null)) ); } diff --git a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts index d3ba1d1daa..cc382c420a 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts +++ b/ui-ngx/src/app/modules/home/pages/widget/widget-editor.component.ts @@ -52,11 +52,11 @@ import { SaveWidgetTypeAsDialogComponent, SaveWidgetTypeAsDialogResult } from '@home/pages/widget/save-widget-type-as-dialog.component'; -import { forkJoin, Subscription } from 'rxjs'; +import { forkJoin, mergeMap, of, Subscription, throwError } from 'rxjs'; import { ResizeObserver } from '@juggle/resize-observer'; import { widgetEditorCompleter } from '@home/pages/widget/widget-editor.models'; import { Observable } from 'rxjs/internal/Observable'; -import { map, tap } from 'rxjs/operators'; +import { catchError, map, tap } from 'rxjs/operators'; import { beautifyCss, beautifyHtml, beautifyJs } from '@shared/models/beautify.models'; import Timeout = NodeJS.Timeout; @@ -543,7 +543,20 @@ export class WidgetEditorComponent extends PageComponent implements OnInit, OnDe private commitSaveWidget() { const id = (this.widgetTypeDetails && this.widgetTypeDetails.id) ? this.widgetTypeDetails.id : undefined; const createdTime = (this.widgetTypeDetails && this.widgetTypeDetails.createdTime) ? this.widgetTypeDetails.createdTime : undefined; - this.widgetService.saveWidgetTypeDetails(this.widget, id, createdTime).subscribe({ + this.widgetService.saveWidgetTypeDetails(this.widget, id, createdTime).pipe( + mergeMap((widgetTypeDetails) => { + const widgetsBundleId = this.route.snapshot.params.widgetsBundleId as string; + if (widgetsBundleId) { + return this.widgetService.addWidgetFqnToWidgetBundle(widgetsBundleId, widgetTypeDetails.fqn).pipe( + map(() => widgetTypeDetails), + catchError((error) => this.widgetService.deleteWidgetType(widgetTypeDetails.id.id).pipe( + mergeMap(() => throwError(() => error)) + )) + ); + } + return of(widgetTypeDetails); + }) + ).subscribe({ next: (widgetTypeDetails) => { this.saveWidgetPending = false; if (!this.widgetTypeDetails?.id) { diff --git a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html index 2d95fd1fdb..fcd36d6f00 100644 --- a/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html +++ b/ui-ngx/src/app/modules/home/pages/widget/widgets-bundle-widgets.component.html @@ -27,6 +27,23 @@ {{ widgetsBundle.title }}: {{ 'widget.widgets' | translate }} + + + + +