From ab58776f04f9b115cc5b148c77746c59e2348cf1 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Wed, 12 Dec 2018 20:02:39 +0200 Subject: [PATCH 01/13] getAttributes black-box-test --- .../device/DeviceActorMessageProcessor.java | 4 +- .../server/msa/AbstractContainerTest.java | 9 ++- .../msa/connectivity/HttpClientTest.java | 59 ++++++++++++++++++- tools/pom.xml | 1 - .../thingsboard/client/tools/RestClient.java | 41 +++++++++++++ 5 files changed, 107 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index e46a95972f..50a4f7d01b 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -16,7 +16,6 @@ package org.thingsboard.server.actors.device; import akka.actor.ActorContext; -import akka.event.LoggingAdapter; import com.datastax.driver.core.utils.UUIDs; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; @@ -42,7 +41,6 @@ import org.thingsboard.server.common.data.rpc.ToDeviceRpcRequestBody; import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.TbMsgDataType; import org.thingsboard.server.common.msg.TbMsgMetaData; -import org.thingsboard.server.common.msg.cluster.ClusterEventMsg; import org.thingsboard.server.common.msg.rpc.ToDeviceRpcRequest; import org.thingsboard.server.common.msg.session.SessionMsgType; import org.thingsboard.server.common.msg.timeout.DeviceActorClientSideRpcTimeoutMsg; @@ -295,7 +293,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { return systemContext.getAttributesService().findAll(tenantId, deviceId, scope); } } else { - return Futures.immediateFuture(Collections.emptyList()); + return systemContext.getAttributesService().findAll(tenantId, deviceId, scope); } } diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java index 4c3ac8362c..bbabc2eb88 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/AbstractContainerTest.java @@ -32,7 +32,8 @@ import org.apache.http.impl.client.HttpClients; import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; import org.apache.http.ssl.SSLContextBuilder; import org.apache.http.ssl.SSLContexts; -import org.junit.*; +import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.rules.TestRule; import org.junit.rules.TestWatcher; import org.junit.runner.Description; @@ -43,7 +44,10 @@ import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.msa.mapper.WsTelemetryResponse; -import javax.net.ssl.*; + +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLSession; +import javax.net.ssl.SSLSocket; import java.net.URI; import java.security.cert.X509Certificate; import java.util.List; @@ -54,6 +58,7 @@ import java.util.Random; public abstract class AbstractContainerTest { protected static final String HTTPS_URL = "https://localhost"; protected static final String WSS_URL = "wss://localhost"; + protected static String TB_TOKEN; protected static RestClient restClient; protected ObjectMapper mapper = new ObjectMapper(); diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java index a6e89de185..a5796cc69a 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.msa.connectivity; +import com.fasterxml.jackson.databind.JsonNode; import com.google.common.collect.Sets; import org.junit.Assert; import org.junit.Test; @@ -25,6 +26,15 @@ import org.thingsboard.server.msa.AbstractContainerTest; import org.thingsboard.server.msa.WsClient; import org.thingsboard.server.msa.mapper.WsTelemetryResponse; + +import java.util.Optional; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.thingsboard.server.common.data.DataConstants.DEVICE; +import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; + public class HttpClientTest extends AbstractContainerTest { @Test @@ -52,6 +62,53 @@ public class HttpClientTest extends AbstractContainerTest { Assert.assertTrue(verify(actualLatestTelemetry, "doubleKey", Double.toString(42.0))); Assert.assertTrue(verify(actualLatestTelemetry, "longKey", Long.toString(73))); - restClient.getRestTemplate().delete(HTTPS_URL + "/api/device/" + device.getId()); + restClient.deleteDevice(device.getId()); + } + + @Test + public void getAttributes() throws Exception { + restClient.login("tenant@thingsboard.org", "tenant"); + TB_TOKEN = restClient.getToken(); + + Device device = createDevice("test"); + String accessToken = restClient.getCredentials(device.getId()).getCredentialsId(); + assertNotNull(accessToken); + + ResponseEntity deviceSharedAttributes = restClient.getRestTemplate() + .postForEntity(HTTPS_URL + "/api/plugins/telemetry/" + DEVICE + "/" + device.getId().toString() + "/attributes/" + SHARED_SCOPE, mapper.readTree(createPayload().toString()), + ResponseEntity.class, + accessToken); + + ResponseEntity deviceClientsAttributes = restClient.getRestTemplate() + .postForEntity(HTTPS_URL + "/api/v1/" + accessToken + "/attributes/", mapper.readTree(createPayload().toString()), + ResponseEntity.class, + accessToken); + + Assert.assertTrue(deviceSharedAttributes.getStatusCode().is2xxSuccessful()); + Assert.assertTrue(deviceClientsAttributes.getStatusCode().is2xxSuccessful()); + + Optional allOptional = restClient.getAttributes(accessToken, null, null); + assertTrue(allOptional.isPresent()); + + JsonNode all = allOptional.get(); + assertEquals(all.get("shared"), mapper.readTree(createPayload().toString())); + assertEquals(all.get("client"), mapper.readTree(createPayload().toString())); + + Optional sharedOptional = restClient.getAttributes(accessToken, null, "stringKey"); + assertTrue(sharedOptional.isPresent()); + + JsonNode shared = sharedOptional.get(); + assertEquals(shared.get("shared").get("stringKey"), mapper.readTree(createPayload().get("stringKey").toString())); + assertEquals(shared.get("client"), mapper.readTree(createPayload().toString())); + + Optional clientOptional = restClient.getAttributes(accessToken, "longKey,stringKey", null); + assertTrue(clientOptional.isPresent()); + + JsonNode client = clientOptional.get(); + assertEquals(client.get("shared"), mapper.readTree(createPayload().toString())); + assertEquals(client.get("client").get("longKey"), mapper.readTree(createPayload().get("longKey").toString())); + assertEquals(client.get("client").get("stringKey"), mapper.readTree(createPayload().get("stringKey").toString())); + + restClient.deleteDevice(device.getId()); } } diff --git a/tools/pom.xml b/tools/pom.xml index c1c1ded1d7..616d894a79 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -23,7 +23,6 @@ 2.2.1-SNAPSHOT thingsboard - org.thingsboard tools jar diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java index 4c8c0a4f37..90bfc01dec 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -107,6 +107,27 @@ public class RestClient implements ClientHttpRequestInterceptor { } } + public Optional getAttributes(String accessToken, String clientKeys, String sharedKeys) { + Map params = new HashMap<>(); + params.put("accessToken", accessToken); + params.put("clientKeys", clientKeys); + params.put("sharedKeys", sharedKeys); + try { + ResponseEntity telemetryEntity = restTemplate.getForEntity(baseURL + "/api/v1/{accessToken}/attributes?clientKeys={clientKeys}&sharedKeys={sharedKeys}", JsonNode.class, params); + return Optional.of(telemetryEntity.getBody()); + } catch (HttpClientErrorException exception) { + if (exception.getStatusCode() == HttpStatus.NOT_FOUND) { + return Optional.empty(); + } else { + throw exception; + } + } + } + + public Customer createCustomer(Customer customer) { + return restTemplate.postForEntity(baseURL + "/api/customer", customer, Customer.class).getBody(); + } + public Customer createCustomer(String title) { Customer customer = new Customer(); customer.setTitle(title); @@ -120,6 +141,14 @@ public class RestClient implements ClientHttpRequestInterceptor { return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); } + public Device createDevice(Device device) { + return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); + } + + public Asset createAsset(Asset asset) { + return restTemplate.postForEntity(baseURL + "/api/asset", asset, Asset.class).getBody(); + } + public Asset createAsset(String name, String type) { Asset asset = new Asset(); asset.setName(name); @@ -131,6 +160,18 @@ public class RestClient implements ClientHttpRequestInterceptor { return restTemplate.postForEntity(baseURL + "/api/alarm", alarm, Alarm.class).getBody(); } + public void deleteCustomer(CustomerId customerId) { + restTemplate.delete(baseURL + "/api/customer/{customerId}", customerId); + } + + public void deleteDevice(DeviceId deviceId) { + restTemplate.delete(baseURL + "/api/device/{deviceId}", deviceId); + } + + public void deleteAsset(AssetId assetId) { + restTemplate.delete(baseURL + "/api/asset/{assetId}", assetId); + } + public Device assignDevice(CustomerId customerId, DeviceId deviceId) { return restTemplate.postForEntity(baseURL + "/api/customer/{customerId}/device/{deviceId}", null, Device.class, customerId.toString(), deviceId.toString()).getBody(); From 50f964e17a28f77eac1b735963b111f58e06b751 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 14 Dec 2018 18:02:20 +0200 Subject: [PATCH 02/13] refactoring getAttributesKvEntries method --- .../device/DeviceActorMessageProcessor.java | 84 ++++++++++++++++--- 1 file changed, 72 insertions(+), 12 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 50a4f7d01b..6f66a77eb2 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -30,7 +30,6 @@ import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.Device; import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.TenantId; @@ -85,6 +84,9 @@ import java.util.UUID; import java.util.function.Consumer; import java.util.stream.Collectors; +import static org.thingsboard.server.common.data.DataConstants.CLIENT_SCOPE; +import static org.thingsboard.server.common.data.DataConstants.SHARED_SCOPE; + /** * @author Andrew Shvayka */ @@ -261,10 +263,8 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { } private void handleGetAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, GetAttributeRequestMsg request) { - ListenableFuture> clientAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.CLIENT_SCOPE, toOptionalSet(request.getClientAttributeNamesList())); - ListenableFuture> sharedAttributesFuture = getAttributeKvEntries(deviceId, DataConstants.SHARED_SCOPE, toOptionalSet(request.getSharedAttributeNamesList())); int requestId = request.getRequestId(); - Futures.addCallback(Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)), new FutureCallback>>() { + Futures.addCallback(getAttributesKvEntries(request), new FutureCallback>>() { @Override public void onSuccess(@Nullable List> result) { GetAttributeResponseMsg responseMsg = GetAttributeResponseMsg.newBuilder() @@ -285,16 +285,76 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { }); } - private ListenableFuture> getAttributeKvEntries(DeviceId deviceId, String scope, Optional> names) { - if (names.isPresent()) { - if (!names.get().isEmpty()) { - return systemContext.getAttributesService().find(tenantId, deviceId, scope, names.get()); + private ListenableFuture>> getAttributesKvEntries(GetAttributeRequestMsg request) { + ListenableFuture> clientAttributesFuture; + ListenableFuture> sharedAttributesFuture; + if (!clientIsPresent(request) && !sharedIsPresent(request)) { + clientAttributesFuture = findAllClientAttributes(); + sharedAttributesFuture = findAllSharedAttributes(); + } else if (clientIsPresent(request) && sharedIsPresent(request)) { + if (clientIsNotEmpty(request) && sharedIsNotEmpty(request)) { + clientAttributesFuture = findClientAttributes(request); + sharedAttributesFuture = findSharedAttributes(request); + } else { + clientAttributesFuture = findAllClientAttributes(); + sharedAttributesFuture = findAllSharedAttributes(); + } + } else if (clientIsPresent(request) && !sharedIsPresent(request)) { + if (clientIsNotEmpty(request)) { + clientAttributesFuture = findClientAttributes(request); } else { - return systemContext.getAttributesService().findAll(tenantId, deviceId, scope); + clientAttributesFuture = findAllClientAttributes(); } + sharedAttributesFuture = Futures.immediateFuture(Collections.emptyList()); } else { - return systemContext.getAttributesService().findAll(tenantId, deviceId, scope); + if (sharedIsNotEmpty(request)) { + sharedAttributesFuture = findSharedAttributes(request); + } else { + sharedAttributesFuture = findAllSharedAttributes(); + } + clientAttributesFuture = Futures.immediateFuture(Collections.emptyList()); } + return Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)); + } + + private ListenableFuture> findAllSharedAttributes() { + return systemContext.getAttributesService().findAll(tenantId, deviceId, SHARED_SCOPE); + } + + private ListenableFuture> findAllClientAttributes() { + return systemContext.getAttributesService().findAll(tenantId, deviceId, CLIENT_SCOPE); + } + + private ListenableFuture> findSharedAttributes(GetAttributeRequestMsg request) { + return systemContext.getAttributesService().find(tenantId, deviceId, SHARED_SCOPE, getSharedAttributesSet(request)); + } + + private ListenableFuture> findClientAttributes(GetAttributeRequestMsg request) { + return systemContext.getAttributesService().find(tenantId, deviceId, CLIENT_SCOPE, getClientAttributesSet(request)); + } + + private boolean clientIsNotEmpty(GetAttributeRequestMsg request) { + return !getClientAttributesSet(request).isEmpty(); + } + + private boolean sharedIsNotEmpty(GetAttributeRequestMsg request) { + return !getSharedAttributesSet(request).isEmpty(); + } + + private Set getSharedAttributesSet(GetAttributeRequestMsg request) { + return toOptionalSet(request.getSharedAttributeNamesList()).get(); + } + + private Set getClientAttributesSet(GetAttributeRequestMsg request) { + return toOptionalSet(request.getClientAttributeNamesList()).get(); + } + + private boolean sharedIsPresent(GetAttributeRequestMsg request) { + return toOptionalSet(request.getSharedAttributeNamesList()).isPresent(); + } + + private boolean clientIsPresent(GetAttributeRequestMsg request) { + return toOptionalSet(request.getClientAttributeNamesList()).isPresent(); } private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { @@ -366,7 +426,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { AttributeUpdateNotificationMsg.Builder notification = AttributeUpdateNotificationMsg.newBuilder(); if (msg.isDeleted()) { List sharedKeys = msg.getDeletedKeys().stream() - .filter(key -> DataConstants.SHARED_SCOPE.equals(key.getScope())) + .filter(key -> SHARED_SCOPE.equals(key.getScope())) .map(AttributeKey::getAttributeKey) .collect(Collectors.toList()); if (!sharedKeys.isEmpty()) { @@ -374,7 +434,7 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { hasNotificationData = true; } } else { - if (DataConstants.SHARED_SCOPE.equals(msg.getScope())) { + if (SHARED_SCOPE.equals(msg.getScope())) { List attributes = new ArrayList<>(msg.getValues()); if (attributes.size() > 0) { List sharedUpdated = msg.getValues().stream().map(this::toTsKvProto) From 90643f397c1a83ea9d6b058af80592bc9c6bbc48 Mon Sep 17 00:00:00 2001 From: Volodymyr Babak Date: Mon, 17 Dec 2018 20:24:06 +0200 Subject: [PATCH 03/13] Fixes for entity_views update schemas --- .../main/data/upgrade/2.1.1/schema_update.cql | 7 ------- .../main/data/upgrade/2.1.1/schema_update.sql | 4 +--- .../org/thingsboard/client/tools/RestClient.java | 16 ++++++++++++++++ 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.cql b/application/src/main/data/upgrade/2.1.1/schema_update.cql index 36ac8e4d38..73793c4ea1 100644 --- a/application/src/main/data/upgrade/2.1.1/schema_update.cql +++ b/application/src/main/data/upgrade/2.1.1/schema_update.cql @@ -14,13 +14,6 @@ -- limitations under the License. -- -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_name; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_search_text; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_customer; -DROP MATERIALIZED VIEW IF EXISTS thingsboard.entity_view_by_tenant_and_entity_id; - -DROP TABLE IF EXISTS thingsboard.entity_views; - CREATE TABLE IF NOT EXISTS thingsboard.entity_views ( id timeuuid, entity_id timeuuid, diff --git a/application/src/main/data/upgrade/2.1.1/schema_update.sql b/application/src/main/data/upgrade/2.1.1/schema_update.sql index bd2c341e7f..ecf90e01ad 100644 --- a/application/src/main/data/upgrade/2.1.1/schema_update.sql +++ b/application/src/main/data/upgrade/2.1.1/schema_update.sql @@ -14,10 +14,8 @@ -- limitations under the License. -- -DROP TABLE IF EXISTS entity_views; - CREATE TABLE IF NOT EXISTS entity_views ( - id varchar(31) NOT NULL CONSTRAINT entity_view_pkey PRIMARY KEY, + id varchar(31) NOT NULL CONSTRAINT entity_views_pkey PRIMARY KEY, entity_id varchar(31), entity_type varchar(255), tenant_id varchar(31), diff --git a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java index 4c8c0a4f37..14f8f9ffe6 100644 --- a/tools/src/main/java/org/thingsboard/client/tools/RestClient.java +++ b/tools/src/main/java/org/thingsboard/client/tools/RestClient.java @@ -36,6 +36,7 @@ import org.thingsboard.server.common.data.id.DeviceId; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.relation.EntityRelation; import org.thingsboard.server.common.data.security.DeviceCredentials; +import org.thingsboard.server.common.data.security.DeviceCredentialsType; import java.io.IOException; import java.util.Collections; @@ -120,6 +121,21 @@ public class RestClient implements ClientHttpRequestInterceptor { return restTemplate.postForEntity(baseURL + "/api/device", device, Device.class).getBody(); } + public void deleteDevice(DeviceId deviceId) { + restTemplate.delete(baseURL + "/api/device/" + deviceId.getId().toString()); + } + + public DeviceCredentials updateDeviceCredentials(DeviceId deviceId, String token) { + DeviceCredentials deviceCredentials = getCredentials(deviceId); + deviceCredentials.setCredentialsType(DeviceCredentialsType.ACCESS_TOKEN); + deviceCredentials.setCredentialsId(token); + return saveDeviceCredentials(deviceCredentials); + } + + public DeviceCredentials saveDeviceCredentials(DeviceCredentials deviceCredentials) { + return restTemplate.postForEntity(baseURL + "/api/device/credentials", deviceCredentials, DeviceCredentials.class).getBody(); + } + public Asset createAsset(String name, String type) { Asset asset = new Asset(); asset.setName(name); From 5291afda8a9f39fcc8f03e2f3e5a729369b0d15b Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Tue, 18 Dec 2018 14:49:49 +0200 Subject: [PATCH 04/13] refactoring getAttributes() test --- .../msa/connectivity/HttpClientTest.java | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java index a5796cc69a..bb3380f554 100644 --- a/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java +++ b/msa/black-box-tests/src/test/java/org/thingsboard/server/msa/connectivity/HttpClientTest.java @@ -28,8 +28,10 @@ import org.thingsboard.server.msa.mapper.WsTelemetryResponse; import java.util.Optional; +import java.util.concurrent.TimeUnit; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.thingsboard.server.common.data.DataConstants.DEVICE; @@ -79,34 +81,39 @@ public class HttpClientTest extends AbstractContainerTest { ResponseEntity.class, accessToken); + Assert.assertTrue(deviceSharedAttributes.getStatusCode().is2xxSuccessful()); + ResponseEntity deviceClientsAttributes = restClient.getRestTemplate() .postForEntity(HTTPS_URL + "/api/v1/" + accessToken + "/attributes/", mapper.readTree(createPayload().toString()), ResponseEntity.class, accessToken); - Assert.assertTrue(deviceSharedAttributes.getStatusCode().is2xxSuccessful()); Assert.assertTrue(deviceClientsAttributes.getStatusCode().is2xxSuccessful()); + TimeUnit.SECONDS.sleep(3); + Optional allOptional = restClient.getAttributes(accessToken, null, null); assertTrue(allOptional.isPresent()); + JsonNode all = allOptional.get(); - assertEquals(all.get("shared"), mapper.readTree(createPayload().toString())); - assertEquals(all.get("client"), mapper.readTree(createPayload().toString())); + assertEquals(2, all.size()); + assertEquals(mapper.readTree(createPayload().toString()), all.get("shared")); + assertEquals(mapper.readTree(createPayload().toString()), all.get("client")); Optional sharedOptional = restClient.getAttributes(accessToken, null, "stringKey"); assertTrue(sharedOptional.isPresent()); JsonNode shared = sharedOptional.get(); assertEquals(shared.get("shared").get("stringKey"), mapper.readTree(createPayload().get("stringKey").toString())); - assertEquals(shared.get("client"), mapper.readTree(createPayload().toString())); + assertFalse(shared.has("client")); Optional clientOptional = restClient.getAttributes(accessToken, "longKey,stringKey", null); assertTrue(clientOptional.isPresent()); JsonNode client = clientOptional.get(); - assertEquals(client.get("shared"), mapper.readTree(createPayload().toString())); - assertEquals(client.get("client").get("longKey"), mapper.readTree(createPayload().get("longKey").toString())); + assertFalse(client.has("shared")); + assertEquals(mapper.readTree(createPayload().get("longKey").toString()), client.get("client").get("longKey")); assertEquals(client.get("client").get("stringKey"), mapper.readTree(createPayload().get("stringKey").toString())); restClient.deleteDevice(device.getId()); From c2d754f9d804cd27209796c2cf579fa390def0e8 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 20 Dec 2018 16:48:47 +0200 Subject: [PATCH 05/13] refactoring getAttributesKvEntries method --- .../device/DeviceActorMessageProcessor.java | 84 +++++-------------- 1 file changed, 19 insertions(+), 65 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index 6f66a77eb2..b250988369 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -78,7 +78,6 @@ import java.util.HashSet; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.function.Consumer; @@ -288,73 +287,36 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { private ListenableFuture>> getAttributesKvEntries(GetAttributeRequestMsg request) { ListenableFuture> clientAttributesFuture; ListenableFuture> sharedAttributesFuture; - if (!clientIsPresent(request) && !sharedIsPresent(request)) { - clientAttributesFuture = findAllClientAttributes(); - sharedAttributesFuture = findAllSharedAttributes(); - } else if (clientIsPresent(request) && sharedIsPresent(request)) { - if (clientIsNotEmpty(request) && sharedIsNotEmpty(request)) { - clientAttributesFuture = findClientAttributes(request); - sharedAttributesFuture = findSharedAttributes(request); - } else { - clientAttributesFuture = findAllClientAttributes(); - sharedAttributesFuture = findAllSharedAttributes(); - } - } else if (clientIsPresent(request) && !sharedIsPresent(request)) { - if (clientIsNotEmpty(request)) { - clientAttributesFuture = findClientAttributes(request); - } else { - clientAttributesFuture = findAllClientAttributes(); - } - sharedAttributesFuture = Futures.immediateFuture(Collections.emptyList()); - } else { - if (sharedIsNotEmpty(request)) { - sharedAttributesFuture = findSharedAttributes(request); - } else { - sharedAttributesFuture = findAllSharedAttributes(); - } + if (listIsEmpty(request.getClientAttributeNamesList()) && listIsEmpty(request.getSharedAttributeNamesList())) { + clientAttributesFuture = findAllAttributesByScope(CLIENT_SCOPE); + sharedAttributesFuture = findAllAttributesByScope(SHARED_SCOPE); + } else if (!listIsEmpty(request.getClientAttributeNamesList()) && !listIsEmpty(request.getSharedAttributeNamesList())) { + clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), CLIENT_SCOPE); + sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); + } else if (listIsEmpty(request.getClientAttributeNamesList()) && !listIsEmpty(request.getSharedAttributeNamesList())) { clientAttributesFuture = Futures.immediateFuture(Collections.emptyList()); + sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); + } else { + sharedAttributesFuture = Futures.immediateFuture(Collections.emptyList()); + clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), CLIENT_SCOPE); } return Futures.allAsList(Arrays.asList(clientAttributesFuture, sharedAttributesFuture)); } - private ListenableFuture> findAllSharedAttributes() { - return systemContext.getAttributesService().findAll(tenantId, deviceId, SHARED_SCOPE); - } - - private ListenableFuture> findAllClientAttributes() { - return systemContext.getAttributesService().findAll(tenantId, deviceId, CLIENT_SCOPE); - } - - private ListenableFuture> findSharedAttributes(GetAttributeRequestMsg request) { - return systemContext.getAttributesService().find(tenantId, deviceId, SHARED_SCOPE, getSharedAttributesSet(request)); - } - - private ListenableFuture> findClientAttributes(GetAttributeRequestMsg request) { - return systemContext.getAttributesService().find(tenantId, deviceId, CLIENT_SCOPE, getClientAttributesSet(request)); - } - - private boolean clientIsNotEmpty(GetAttributeRequestMsg request) { - return !getClientAttributesSet(request).isEmpty(); - } - - private boolean sharedIsNotEmpty(GetAttributeRequestMsg request) { - return !getSharedAttributesSet(request).isEmpty(); + private ListenableFuture> findAllAttributesByScope(String scope) { + return systemContext.getAttributesService().findAll(tenantId, deviceId, scope); } - private Set getSharedAttributesSet(GetAttributeRequestMsg request) { - return toOptionalSet(request.getSharedAttributeNamesList()).get(); + private ListenableFuture> findAttributesByScope(Set attributesSet, String scope) { + return systemContext.getAttributesService().find(tenantId, deviceId, scope, attributesSet); } - private Set getClientAttributesSet(GetAttributeRequestMsg request) { - return toOptionalSet(request.getClientAttributeNamesList()).get(); + private Set toSet(List strings) { + return new HashSet<>(strings); } - private boolean sharedIsPresent(GetAttributeRequestMsg request) { - return toOptionalSet(request.getSharedAttributeNamesList()).isPresent(); - } - - private boolean clientIsPresent(GetAttributeRequestMsg request) { - return toOptionalSet(request.getClientAttributeNamesList()).isPresent(); + private boolean listIsEmpty(List strings) { + return strings == null || strings.isEmpty(); } private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { @@ -603,14 +565,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { return json; } - private Optional> toOptionalSet(List strings) { - if (strings == null || strings.isEmpty()) { - return Optional.empty(); - } else { - return Optional.of(new HashSet<>(strings)); - } - } - private void sendToTransport(GetAttributeResponseMsg responseMsg, SessionInfoProto sessionInfo) { DeviceActorToTransportMsg msg = DeviceActorToTransportMsg.newBuilder() .setSessionIdMSB(sessionInfo.getSessionIdMSB()) From 379682a4adde5a0ed5aae8fa87daffd8e1ec8204 Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Thu, 20 Dec 2018 17:20:37 +0200 Subject: [PATCH 06/13] refactoring DeviceActorMessageProcessor.java --- .../actors/device/DeviceActorMessageProcessor.java | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java index b250988369..c0030cbf6d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessor.java @@ -25,6 +25,7 @@ import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.protobuf.InvalidProtocolBufferException; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.collections.CollectionUtils; import org.thingsboard.rule.engine.api.RpcError; import org.thingsboard.rule.engine.api.msg.DeviceAttributesEventNotificationMsg; import org.thingsboard.rule.engine.api.msg.DeviceNameOrTypeUpdateMsg; @@ -287,13 +288,13 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { private ListenableFuture>> getAttributesKvEntries(GetAttributeRequestMsg request) { ListenableFuture> clientAttributesFuture; ListenableFuture> sharedAttributesFuture; - if (listIsEmpty(request.getClientAttributeNamesList()) && listIsEmpty(request.getSharedAttributeNamesList())) { + if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { clientAttributesFuture = findAllAttributesByScope(CLIENT_SCOPE); sharedAttributesFuture = findAllAttributesByScope(SHARED_SCOPE); - } else if (!listIsEmpty(request.getClientAttributeNamesList()) && !listIsEmpty(request.getSharedAttributeNamesList())) { + } else if (!CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { clientAttributesFuture = findAttributesByScope(toSet(request.getClientAttributeNamesList()), CLIENT_SCOPE); sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); - } else if (listIsEmpty(request.getClientAttributeNamesList()) && !listIsEmpty(request.getSharedAttributeNamesList())) { + } else if (CollectionUtils.isEmpty(request.getClientAttributeNamesList()) && !CollectionUtils.isEmpty(request.getSharedAttributeNamesList())) { clientAttributesFuture = Futures.immediateFuture(Collections.emptyList()); sharedAttributesFuture = findAttributesByScope(toSet(request.getSharedAttributeNamesList()), SHARED_SCOPE); } else { @@ -315,10 +316,6 @@ class DeviceActorMessageProcessor extends AbstractContextAwareMsgProcessor { return new HashSet<>(strings); } - private boolean listIsEmpty(List strings) { - return strings == null || strings.isEmpty(); - } - private void handlePostAttributesRequest(ActorContext context, SessionInfoProto sessionInfo, PostAttributeMsg postAttributes) { JsonObject json = getJsonObject(postAttributes.getKvList()); TbMsg tbMsg = new TbMsg(UUIDs.timeBased(), SessionMsgType.POST_ATTRIBUTES_REQUEST.name(), deviceId, defaultMetaData.copy(), From dfe2586e616ebbaa1217da0074694d972a9063dc Mon Sep 17 00:00:00 2001 From: ShvaykaD Date: Fri, 21 Dec 2018 16:15:17 +0200 Subject: [PATCH 07/13] fix TbGetTelemetryNode (#1353) TbGetTelemetryNode - get start and end ts from metadata --- .../engine/metadata/TbGetTelemetryNode.java | 108 +++++++++++++++--- .../TbGetTelemetryNodeConfiguration.java | 9 ++ .../static/rulenode/rulenode-core-config.js | 8 +- 3 files changed, 106 insertions(+), 19 deletions(-) diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java index 66569b70bf..b04b5b36c1 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNode.java @@ -21,8 +21,15 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.node.ArrayNode; import com.fasterxml.jackson.databind.node.ObjectNode; import com.google.common.util.concurrent.ListenableFuture; +import lombok.Data; +import lombok.NoArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.thingsboard.rule.engine.api.*; +import org.apache.commons.lang3.math.NumberUtils; +import org.thingsboard.rule.engine.api.RuleNode; +import org.thingsboard.rule.engine.api.TbContext; +import org.thingsboard.rule.engine.api.TbNode; +import org.thingsboard.rule.engine.api.TbNodeConfiguration; +import org.thingsboard.rule.engine.api.TbNodeException; import org.thingsboard.rule.engine.api.util.DonAsynchron; import org.thingsboard.rule.engine.api.util.TbNodeUtils; import org.thingsboard.server.common.data.kv.BaseReadTsKvQuery; @@ -37,7 +44,9 @@ import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import static org.thingsboard.rule.engine.api.TbRelationTypes.SUCCESS; -import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.*; +import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.FETCH_MODE_ALL; +import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.FETCH_MODE_FIRST; +import static org.thingsboard.rule.engine.metadata.TbGetTelemetryNodeConfiguration.MAX_FETCH_SIZE; import static org.thingsboard.server.common.data.kv.Aggregation.NONE; /** @@ -57,8 +66,6 @@ public class TbGetTelemetryNode implements TbNode { private TbGetTelemetryNodeConfiguration config; private List tsKeyNames; - private long startTsOffset; - private long endTsOffset; private int limit; private ObjectMapper mapper; private String fetchMode; @@ -67,8 +74,6 @@ public class TbGetTelemetryNode implements TbNode { public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { this.config = TbNodeUtils.convert(configuration, TbGetTelemetryNodeConfiguration.class); tsKeyNames = config.getLatestTsKeyNames(); - startTsOffset = TimeUnit.valueOf(config.getStartIntervalTimeUnit()).toMillis(config.getStartInterval()); - endTsOffset = TimeUnit.valueOf(config.getEndIntervalTimeUnit()).toMillis(config.getEndInterval()); limit = config.getFetchMode().equals(FETCH_MODE_ALL) ? MAX_FETCH_SIZE : 1; fetchMode = config.getFetchMode(); mapper = new ObjectMapper(); @@ -82,8 +87,8 @@ public class TbGetTelemetryNode implements TbNode { ctx.tellFailure(msg, new IllegalStateException("Telemetry is not selected!")); } else { try { - List queries = buildQueries(); - ListenableFuture> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), queries); + checkMetadataKeyPatterns(msg); + ListenableFuture> list = ctx.getTimeseriesService().findAll(ctx.getTenantId(), msg.getOriginator(), buildQueries(msg)); DonAsynchron.withCallback(list, data -> { process(data, msg); TbMsg newMsg = ctx.transformMsg(msg, msg.getType(), msg.getOriginator(), msg.getMetaData(), msg.getData()); @@ -95,10 +100,12 @@ public class TbGetTelemetryNode implements TbNode { } } - private List buildQueries() { - long ts = System.currentTimeMillis(); - long startTs = ts - startTsOffset; - long endTs = ts - endTsOffset; + @Override + public void destroy() { + + } + + private List buildQueries(TbMsg msg) { String orderBy; if (fetchMode.equals(FETCH_MODE_FIRST) || fetchMode.equals(FETCH_MODE_ALL)) { orderBy = "ASC"; @@ -106,7 +113,7 @@ public class TbGetTelemetryNode implements TbNode { orderBy = "DESC"; } return tsKeyNames.stream() - .map(key -> new BaseReadTsKvQuery(key, startTs, endTs, 1, limit, NONE, orderBy)) + .map(key -> new BaseReadTsKvQuery(key, getInterval(msg).getStartTs(), getInterval(msg).getEndTs(), 1, limit, NONE, orderBy)) .collect(Collectors.toList()); } @@ -162,8 +169,79 @@ public class TbGetTelemetryNode implements TbNode { return obj; } - @Override - public void destroy() { + private Interval getInterval(TbMsg msg) { + Interval interval = new Interval(); + if (config.isUseMetadataIntervalPatterns()) { + if (isParsable(msg, config.getStartIntervalPattern())) { + interval.setStartTs(Long.parseLong(TbNodeUtils.processPattern(config.getStartIntervalPattern(), msg.getMetaData()))); + } + if (isParsable(msg, config.getEndIntervalPattern())) { + interval.setEndTs(Long.parseLong(TbNodeUtils.processPattern(config.getEndIntervalPattern(), msg.getMetaData()))); + } + } else { + long ts = System.currentTimeMillis(); + interval.setStartTs(ts - TimeUnit.valueOf(config.getStartIntervalTimeUnit()).toMillis(config.getStartInterval())); + interval.setEndTs(ts - TimeUnit.valueOf(config.getEndIntervalTimeUnit()).toMillis(config.getEndInterval())); + } + return interval; + } + + private boolean isParsable(TbMsg msg, String pattern) { + return NumberUtils.isParsable(TbNodeUtils.processPattern(pattern, msg.getMetaData())); + } + private void checkMetadataKeyPatterns(TbMsg msg) { + isUndefined(msg, config.getStartIntervalPattern(), config.getEndIntervalPattern()); + isInvalid(msg, config.getStartIntervalPattern(), config.getEndIntervalPattern()); } + + private void isUndefined(TbMsg msg, String startIntervalPattern, String endIntervalPattern) { + if (getMetadataValue(msg, startIntervalPattern) == null && getMetadataValue(msg, endIntervalPattern) == null) { + throw new IllegalArgumentException("Message metadata values: '" + + replaceRegex(startIntervalPattern) + "' and '" + + replaceRegex(endIntervalPattern) + "' are undefined"); + } else { + if (getMetadataValue(msg, startIntervalPattern) == null) { + throw new IllegalArgumentException("Message metadata value: '" + + replaceRegex(startIntervalPattern) + "' is undefined"); + } + if (getMetadataValue(msg, endIntervalPattern) == null) { + throw new IllegalArgumentException("Message metadata value: '" + + replaceRegex(endIntervalPattern) + "' is undefined"); + } + } + } + + private void isInvalid(TbMsg msg, String startIntervalPattern, String endIntervalPattern) { + if (getInterval(msg).getStartTs() == null && getInterval(msg).getEndTs() == null) { + throw new IllegalArgumentException("Message metadata values: '" + + replaceRegex(startIntervalPattern) + "' and '" + + replaceRegex(endIntervalPattern) + "' have invalid format"); + } else { + if (getInterval(msg).getStartTs() == null) { + throw new IllegalArgumentException("Message metadata value: '" + + replaceRegex(startIntervalPattern) + "' has invalid format"); + } + if (getInterval(msg).getEndTs() == null) { + throw new IllegalArgumentException("Message metadata value: '" + + replaceRegex(endIntervalPattern) + "' has invalid format"); + } + } + } + + private String getMetadataValue(TbMsg msg, String pattern) { + return msg.getMetaData().getValue(replaceRegex(pattern)); + } + + private String replaceRegex(String pattern) { + return pattern.replaceAll("[${}]", ""); + } + + @Data + @NoArgsConstructor + private static class Interval { + private Long startTs; + private Long endTs; + } + } diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeConfiguration.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeConfiguration.java index 37ce0af42b..31bacf9559 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeConfiguration.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/metadata/TbGetTelemetryNodeConfiguration.java @@ -35,6 +35,12 @@ public class TbGetTelemetryNodeConfiguration implements NodeConfiguration
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"},function(e,t){e.exports="
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }}
tb.rulenode.headers-hint
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'; -},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
'},function(e,t){e.exports='
{{ type }}
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
'},function(e,t){e.exports='
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},28,function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(6),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(7),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,i){var r=function(r,a,l,s){var u=o.default;a.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(a.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(8),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,i){var r=function(r,a,l,s){var u=o.default;a.html(u),r.types=n,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue},r.testDetailsBuildJs=function(e){var n=angular.copy(r.configuration.alarmDetailsBuildJs);i.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(a.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(9),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(10),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(11),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n,i){var r=function(r,a,l,s){var u=o.default;a.html(u),r.types=n,r.originator=null,r.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(r.configuration)}),s.$render=function(){r.configuration=s.$viewValue,r.configuration.originatorId&&r.configuration.originatorType?r.originator={id:r.configuration.originatorId,entityType:r.configuration.originatorType}:r.originator=null,r.$watch("originator",function(e,t){angular.equals(e,t)||(r.originator?(s.$viewValue.originatorId=r.originator.id,s.$viewValue.originatorType=r.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},r.testScript=function(e){var n=angular.copy(r.configuration.jsScript);i.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],r.ruleNodeId).then(function(e){r.configuration.jsScript=e,s.$setDirty()})},e(a.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}r.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(1);var a=n(12),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(65),a=i(r),o=n(46),l=i(o),s=n(51),u=i(s),d=n(48),c=i(d),m=n(47),g=i(m),p=n(54),f=i(p),b=n(60),v=i(b),y=n(61),q=i(y),h=n(59),$=i(h),x=n(53),T=i(x),k=n(63),C=i(k),w=n(64),M=i(w),_=n(58),S=i(_),N=n(55),E=i(N),V=n(62),P=i(V),F=n(57),j=i(F),A=n(56),O=i(A),I=n(45),R=i(I),K=n(66),D=i(K),U=n(50),L=i(U),z=n(49),B=i(z);t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",a.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",u.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",q.default).directive("tbActionNodeRestApiCallConfig",$.default).directive("tbActionNodeKafkaConfig",T.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",P.default).directive("tbActionNodeMsgDelayConfig",j.default).directive("tbActionNodeMsgCountConfig",O.default).directive("tbActionNodeAssignToCustomerConfig",R.default).directive("tbActionNodeUnAssignToCustomerConfig",D.default).directive("tbActionNodeDeleteRelationConfig",L.default).directive("tbActionNodeCreateRelationConfig",B.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel", -scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(13),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var i=function(i,r,a,l){var s=o.default;r.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var r=angular.copy(i.configuration.jsScript);n.testNodeScript(e,r,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(14),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var i=function(i,r,a,l){var s=o.default;r.html(s),i.$mdExpansionPanel=t,i.ruleNodeTypes=n,i.credentialsTypeChanged=function(){var e=i.configuration.credentials.type;i.configuration.credentials={},i.configuration.credentials.type=e,i.updateValidity()},i.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){i.$apply(function(){if(n.target.result){l.$setDirty();var r=n.target.result;r&&r.length>0&&("caCert"==t&&(i.configuration.credentials.caCertFileName=e.name,i.configuration.credentials.caCert=r),"privateKey"==t&&(i.configuration.credentials.privateKeyFileName=e.name,i.configuration.credentials.privateKey=r),"Cert"==t&&(i.configuration.credentials.certFileName=e.name,i.configuration.credentials.cert=r)),i.updateValidity()}})},n.readAsText(e.file)},i.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(i.configuration.credentials.caCertFileName=null,i.configuration.credentials.caCert=null),"privateKey"==e&&(i.configuration.credentials.privateKeyFileName=null,i.configuration.credentials.privateKey=null),"Cert"==e&&(i.configuration.credentials.certFileName=null,i.configuration.credentials.cert=null),i.updateValidity()},i.updateValidity=function(){var e=!0,t=i.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(r.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:i}}r.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r,n(2);var a=n(15),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(16),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(17),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(18),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(19),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(20),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(21),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(22),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(23),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(24),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(25),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(26),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||a.$setViewValue(n.query)}),a.$render=function(){n.query=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(27),o=i(a)},function(e,t){"use strict";function n(e){var t=function(t,n,i,r){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(28),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(29),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var i=function(i,r,a,l){var s=o.default;r.html(s);var u=186;i.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,u],i.ruleNodeTypes=n,i.aggPeriodTimeUnits={},i.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,i.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,i.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,i.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,i.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},e(r.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{},link:i}}r.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(30),o=i(a);n(3)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(73),a=i(r),o=n(74),l=i(o),s=n(70),u=i(s),d=n(75),c=i(d),m=n(69),g=i(m),p=n(76),f=i(p),b=n(71),v=i(b);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",a.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",u.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(31),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(32),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(33),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(34),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(35),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(81),a=i(r),o=n(79),l=i(o),s=n(82),u=i(s),d=n(77),c=i(d),m=n(80),g=i(m);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",a.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",u.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var i=function(i,r,a,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),r.$setViewValue(e),u()}function u(){var e=!0;t.required&&!t.kvList.length&&(e=!1),r.$setValidity("kvMap",e)}var d=o.default;n.html(d),t.ngModelCtrl=r,t.removeKeyVal=a,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||r.$setViewValue(t.query)}),r.$render=function(){if(r.$viewValue){var e=r.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),u()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(40),o=i(a);n(5)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||a.$setViewValue(n.query)}),a.$render=function(){n.query=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(41),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t){var n=function(n,i,r,a){var l=o.default;i.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(i.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}r.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(42),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(85),a=i(r),o=n(87),l=i(o),s=n(88),u=i(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",a.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",u.default).name},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e,t,n){var i=function(i,r,a,l){var s=o.default;r.html(s),i.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(i.configuration)}),l.$render=function(){i.configuration=l.$viewValue},i.testScript=function(e){var r=angular.copy(i.configuration.jsScript);n.testNodeScript(e,r,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,l.$setDirty()})},e(r.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}r.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(43),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){var t=function(t,n,i,r){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||r.$setViewValue(t.configuration)}),r.$render=function(){t.configuration=r.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}r.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(44),o=i(a)},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var r=n(92),a=i(r),o=n(78),l=i(o),s=n(72),u=i(s),d=n(86),c=i(d),m=n(52),g=i(m),p=n(68),f=i(p),b=n(84),v=i(b),y=n(67),q=i(y),h=n(83),$=i(h),x=n(91),T=i(x);t.default=angular.module("thingsboard.ruleChain.config",[a.default,l.default,u.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",q.default).directive("tbKvMapConfig",$.default).config(T.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647'.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","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.","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","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","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"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","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","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."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}function r(e){(0,o.default)(e)}r.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=r;var a=n(90),o=i(a)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"}},fetchModeType:["FIRST","LAST","ALL"],httpRequestType:["GET","POST","PUT","DELETE"],sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); +!function(e){function t(r){if(n[r])return n[r].exports;var i=n[r]={exports:{},id:r,loaded:!1};return e[r].call(i.exports,i,i.exports,t),i.loaded=!0,i.exports}var n={};return t.m=e,t.c=n,t.p="/static/",t(0)}(function(e){for(var t in e)if(Object.prototype.hasOwnProperty.call(e,t))switch(typeof e[t]){case"function":break;case"object":e[t]=function(t){var n=t.slice(1),r=e[t[0]];return function(e,t,i){r.apply(this,[e,t,i].concat(n))}}(e[t]);break;default:e[t]=e[e[t]]}return e}([function(e,t,n){e.exports=n(89)},function(e,t){},1,1,1,1,function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
{{ 'tb.rulenode.create-customer-if-not-exists' | translate }}
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{scope.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-details-function' | translate }}
tb.rulenode.alarm-type-required
{{ severity.name | translate}}
tb.rulenode.alarm-severity-required
{{ 'tb.rulenode.propagate' | translate }}
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-type-pattern-required
tb.rulenode.entity-type-pattern-hint
{{ 'tb.rulenode.create-entity-if-not-exists' | translate }}
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
tb.rulenode.entity-name-pattern-required
tb.rulenode.entity-name-pattern-hint
tb.rulenode.entity-cache-expiration-required
tb.rulenode.entity-cache-expiration-range
tb.rulenode.entity-cache-expiration-hint
"},function(e,t){e.exports="
tb.rulenode.message-count-required
tb.rulenode.min-message-count-message
tb.rulenode.period-seconds-required
tb.rulenode.min-period-seconds-message
{{ 'tb.rulenode.test-generator-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.bootstrap-servers-required
tb.rulenode.min-retries-message
tb.rulenode.min-batch-size-bytes-message
tb.rulenode.min-linger-ms-message
tb.rulenode.min-buffer-memory-bytes-message
{{ ackValue }}
tb.rulenode.key-serializer-required
tb.rulenode.value-serializer-required
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-to-string-function' | translate }}
"},function(e,t){e.exports='
tb.rulenode.topic-pattern-required
tb.rulenode.mqtt-topic-pattern-hint
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
tb.rulenode.connect-timeout-required
tb.rulenode.connect-timeout-range
tb.rulenode.connect-timeout-range
{{ \'tb.rulenode.clean-session\' | translate }} {{ \'tb.rulenode.enable-ssl\' | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{ \'tb.rulenode.credentials\' | translate }}
{{ ruleNodeTypes.mqttCredentialTypes[configuration.credentials.type].name | translate }}
{{credentialsValue.name | translate}}
tb.rulenode.credentials-type-required
tb.rulenode.username-required
tb.rulenode.password-required
'},function(e,t){e.exports="
tb.rulenode.interval-seconds-required
tb.rulenode.min-interval-seconds-message
tb.rulenode.output-timeseries-key-prefix-required
"},function(e,t){e.exports="
tb.rulenode.period-seconds-required
tb.rulenode.min-period-0-seconds-message
tb.rulenode.max-pending-messages-required
tb.rulenode.max-pending-messages-range
tb.rulenode.max-pending-messages-range
"},function(e,t){e.exports='
{{ property }}
tb.rulenode.host-required
tb.rulenode.port-required
tb.rulenode.port-range
tb.rulenode.port-range
{{ \'tb.rulenode.automatic-recovery\' | translate }}
tb.rulenode.min-connection-timeout-ms-message
tb.rulenode.min-handshake-timeout-ms-message
'},function(e,t){e.exports='
tb.rulenode.endpoint-url-pattern-required
tb.rulenode.endpoint-url-pattern-hint
{{ type }}
tb.rulenode.headers-hint
'},function(e,t){e.exports="
"},function(e,t){e.exports="
tb.rulenode.timeout-required
tb.rulenode.min-timeout-message
"},function(e,t){e.exports='
{{ \'tb.rulenode.use-system-smtp-settings\' | translate }}
{{smtpProtocol.toUpperCase()}}
tb.rulenode.smtp-host-required
tb.rulenode.smtp-port-required
tb.rulenode.smtp-port-range
tb.rulenode.smtp-port-range
tb.rulenode.timeout-required
tb.rulenode.min-timeout-msec-message
{{ \'tb.rulenode.enable-tls\' | translate }}
'; +},function(e,t){e.exports="
tb.rulenode.topic-arn-pattern-required
tb.rulenode.topic-arn-pattern-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
"},function(e,t){e.exports='
{{ type.name | translate }}
tb.rulenode.queue-url-pattern-required
tb.rulenode.queue-url-pattern-hint
tb.rulenode.min-delay-seconds-message
tb.rulenode.max-delay-seconds-message
tb.rulenode.message-attributes-hint
tb.rulenode.aws-access-key-id-required
tb.rulenode.aws-secret-access-key-required
tb.rulenode.aws-region-required
'},function(e,t){e.exports="
tb.rulenode.default-ttl-required
tb.rulenode.min-default-ttl-message
"},function(e,t){e.exports="
tb.rulenode.customer-name-pattern-required
tb.rulenode.customer-name-pattern-hint
tb.rulenode.customer-cache-expiration-required
tb.rulenode.customer-cache-expiration-range
tb.rulenode.customer-cache-expiration-hint
"},function(e,t){e.exports='
{{ (\'relation.search-direction.\' + direction) | translate}}
relation.relation-type
device.device-types
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},function(e,t){e.exports='
'},function(e,t){e.exports='
{{ type }} {{ \'tb.rulenode.use-metadata-interval-patterns\' | translate }}
tb.rulenode.start-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.end-interval-value-required
tb.rulenode.time-value-range
tb.rulenode.time-value-range
{{timeUnit.name | translate}}
tb.rulenode.start-interval-pattern-required
tb.rulenode.start-interval-pattern-hint
tb.rulenode.end-interval-pattern-required
tb.rulenode.end-interval-pattern-hint
'},function(e,t){e.exports='
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.latest-telemetry' | translate }}
"},28,function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
"},function(e,t){e.exports='
{{item}}
tb.rulenode.no-message-types-found
tb.rulenode.no-message-type-matching tb.rulenode.create-new-message-type
{{$chip.name}}
'},function(e,t){e.exports='
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-filter-function' | translate }}
"},function(e,t){e.exports="
{{ 'tb.rulenode.test-switch-function' | translate }}
"},function(e,t){e.exports='
{{ keyText }} {{ valText }}  
{{keyRequiredText}}
{{valRequiredText}}
{{ \'tb.key-val.remove-entry\' | translate }} close
{{ \'tb.key-val.add-entry\' | translate }} add {{ \'action.add\' | translate }}
'},function(e,t){e.exports="
{{ ('relation.search-direction.' + direction) | translate}}
relation.relation-filters
"},function(e,t){e.exports='
{{ source.name | translate}}
'},function(e,t){e.exports="
{{ 'tb.rulenode.test-transformer-function' | translate }}
"},function(e,t){e.exports="
tb.rulenode.from-template-required
tb.rulenode.from-template-hint
tb.rulenode.to-template-required
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.mail-address-list-template-hint
tb.rulenode.subject-template-required
tb.rulenode.subject-template-hint
tb.rulenode.body-template-required
tb.rulenode.body-template-hint
"},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(6),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(7),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n,r){var i=function(i,a,l,s){var u=o.default;a.html(u),i.types=n,i.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(i.configuration)}),s.$render=function(){i.configuration=s.$viewValue},i.testDetailsBuildJs=function(e){var n=angular.copy(i.configuration.alarmDetailsBuildJs);r.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}i.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(8),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n,r){var i=function(i,a,l,s){var u=o.default;a.html(u),i.types=n,i.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(i.configuration)}),s.$render=function(){i.configuration=s.$viewValue},i.testDetailsBuildJs=function(e){var n=angular.copy(i.configuration.alarmDetailsBuildJs);r.testNodeScript(e,n,"json",t.instant("tb.rulenode.details")+"","Details",["msg","metadata","msgType"],i.ruleNodeId).then(function(e){i.configuration.alarmDetailsBuildJs=e,s.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}i.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(9),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(10),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(11),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n,r){var i=function(i,a,l,s){var u=o.default;a.html(u),i.types=n,i.originator=null,i.$watch("configuration",function(e,t){angular.equals(e,t)||s.$setViewValue(i.configuration)}),s.$render=function(){i.configuration=s.$viewValue,i.configuration.originatorId&&i.configuration.originatorType?i.originator={id:i.configuration.originatorId,entityType:i.configuration.originatorType}:i.originator=null,i.$watch("originator",function(e,t){angular.equals(e,t)||(i.originator?(s.$viewValue.originatorId=i.originator.id,s.$viewValue.originatorType=i.originator.entityType):(s.$viewValue.originatorId=null,s.$viewValue.originatorType=null))},!0)},i.testScript=function(e){var n=angular.copy(i.configuration.jsScript);r.testNodeScript(e,n,"generate",t.instant("tb.rulenode.generator")+"","Generate",["prevMsg","prevMetadata","prevMsgType"],i.ruleNodeId).then(function(e){i.configuration.jsScript=e,s.$setDirty()})},e(a.contents())(i)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:i}}i.$inject=["$compile","$translate","types","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i,n(1);var a=n(12),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(65),a=r(i),o=n(46),l=r(o),s=n(51),u=r(s),d=n(48),c=r(d),m=n(47),g=r(m),p=n(54),f=r(p),b=n(60),v=r(b),y=n(61),q=r(y),h=n(59),$=r(h),x=n(53),T=r(x),k=n(63),C=r(k),w=n(64),M=r(w),_=n(58),S=r(_),N=n(55),E=r(N),P=n(62),V=r(P),F=n(57),j=r(F),A=n(56),I=r(A),O=n(45),K=r(O),R=n(66),D=r(R),U=n(50),L=r(U),z=n(49),B=r(z); +t.default=angular.module("thingsboard.ruleChain.config.action",[]).directive("tbActionNodeTimeseriesConfig",a.default).directive("tbActionNodeAttributesConfig",l.default).directive("tbActionNodeGeneratorConfig",u.default).directive("tbActionNodeCreateAlarmConfig",c.default).directive("tbActionNodeClearAlarmConfig",g.default).directive("tbActionNodeLogConfig",f.default).directive("tbActionNodeRpcReplyConfig",v.default).directive("tbActionNodeRpcRequestConfig",q.default).directive("tbActionNodeRestApiCallConfig",$.default).directive("tbActionNodeKafkaConfig",T.default).directive("tbActionNodeSnsConfig",C.default).directive("tbActionNodeSqsConfig",M.default).directive("tbActionNodeRabbitMqConfig",S.default).directive("tbActionNodeMqttConfig",E.default).directive("tbActionNodeSendEmailConfig",V.default).directive("tbActionNodeMsgDelayConfig",j.default).directive("tbActionNodeMsgCountConfig",I.default).directive("tbActionNodeAssignToCustomerConfig",K.default).directive("tbActionNodeUnAssignToCustomerConfig",D.default).directive("tbActionNodeDeleteRelationConfig",L.default).directive("tbActionNodeCreateRelationConfig",B.default).name},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.ackValues=["all","-1","0","1"],t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(13),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=function(r,i,a,l){var s=o.default;i.html(s),r.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(r.configuration)}),l.$render=function(){r.configuration=l.$viewValue},r.testScript=function(e){var i=angular.copy(r.configuration.jsScript);n.testNodeScript(e,i,"string",t.instant("tb.rulenode.to-string")+"","ToString",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.jsScript=e,l.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}i.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(14),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=function(r,i,a,l){var s=o.default;i.html(s),r.$mdExpansionPanel=t,r.ruleNodeTypes=n,r.credentialsTypeChanged=function(){var e=r.configuration.credentials.type;r.configuration.credentials={},r.configuration.credentials.type=e,r.updateValidity()},r.certFileAdded=function(e,t){var n=new FileReader;n.onload=function(n){r.$apply(function(){if(n.target.result){l.$setDirty();var i=n.target.result;i&&i.length>0&&("caCert"==t&&(r.configuration.credentials.caCertFileName=e.name,r.configuration.credentials.caCert=i),"privateKey"==t&&(r.configuration.credentials.privateKeyFileName=e.name,r.configuration.credentials.privateKey=i),"Cert"==t&&(r.configuration.credentials.certFileName=e.name,r.configuration.credentials.cert=i)),r.updateValidity()}})},n.readAsText(e.file)},r.clearCertFile=function(e){l.$setDirty(),"caCert"==e&&(r.configuration.credentials.caCertFileName=null,r.configuration.credentials.caCert=null),"privateKey"==e&&(r.configuration.credentials.privateKeyFileName=null,r.configuration.credentials.privateKey=null),"Cert"==e&&(r.configuration.credentials.certFileName=null,r.configuration.credentials.cert=null),r.updateValidity()},r.updateValidity=function(){var e=!0,t=r.configuration.credentials;t.type==n.mqttCredentialTypes["cert.PEM"].value&&(t.caCert&&t.cert&&t.privateKey||(e=!1)),l.$setValidity("Certs",e)},r.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(r.configuration)}),l.$render=function(){r.configuration=l.$viewValue},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:r}}i.$inject=["$compile","$mdExpansionPanel","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i,n(2);var a=n(15),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(16),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(17),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.messageProperties=[null,"BASIC","TEXT_PLAIN","MINIMAL_BASIC","MINIMAL_PERSISTENT_BASIC","PERSISTENT_BASIC","PERSISTENT_TEXT_PLAIN"],t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(18),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(19),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(20),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(21),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.smtpProtocols=["smtp","smtps"],t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(22),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(23),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{readonly:"=ngReadonly"},link:n}}i.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(24),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(25),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(26),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||a.$setViewValue(n.query)}),a.$render=function(){n.query=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(27),o=r(a)},function(e,t){"use strict";function n(e){var t=function(t,n,r,i){n.html("
"),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}n.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(28),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(29),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=function(r,i,a,l){var s=o.default;i.html(s);var u=186;r.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,u],r.ruleNodeTypes=n,r.aggPeriodTimeUnits={},r.aggPeriodTimeUnits.MINUTES=n.timeUnit.MINUTES,r.aggPeriodTimeUnits.HOURS=n.timeUnit.HOURS,r.aggPeriodTimeUnits.DAYS=n.timeUnit.DAYS,r.aggPeriodTimeUnits.MILLISECONDS=n.timeUnit.MILLISECONDS,r.aggPeriodTimeUnits.SECONDS=n.timeUnit.SECONDS,r.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(r.configuration)}),l.$render=function(){r.configuration=l.$viewValue},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{},link:r}}i.$inject=["$compile","$mdConstant","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(30),o=r(a);n(3)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(73),a=r(i),o=n(74),l=r(o),s=n(70),u=r(s),d=n(75),c=r(d),m=n(69),g=r(m),p=n(76),f=r(p),b=n(71),v=r(b);t.default=angular.module("thingsboard.ruleChain.config.enrichment",[]).directive("tbEnrichmentNodeOriginatorAttributesConfig",a.default).directive("tbEnrichmentNodeOriginatorFieldsConfig",l.default).directive("tbEnrichmentNodeDeviceAttributesConfig",u.default).directive("tbEnrichmentNodeRelatedAttributesConfig",c.default).directive("tbEnrichmentNodeCustomerAttributesConfig",g.default).directive("tbEnrichmentNodeTenantAttributesConfig",f.default).directive("tbEnrichmentNodeGetTelemetryFromDatabase",v.default).name},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l);var s=186;n.separatorKeys=[t.KEY_CODE.ENTER,t.KEY_CODE.COMMA,s],n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","$mdConstant"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(31),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(32),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(33),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(34),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(35),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(81),a=r(i),o=n(79),l=r(o),s=n(82),u=r(s),d=n(77),c=r(d),m=n(80),g=r(m);t.default=angular.module("thingsboard.ruleChain.config.filter",[]).directive("tbFilterNodeScriptConfig",a.default).directive("tbFilterNodeMessageTypeConfig",l.default).directive("tbFilterNodeSwitchConfig",u.default).directive("tbFilterNodeCheckRelationConfig",c.default).directive("tbFilterNodeOriginatorTypeConfig",g.default).name},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=function(r,i,a,l){function s(){if(l.$viewValue){for(var e=[],t=0;t-1&&t.kvList.splice(e,1)}function l(){t.kvList||(t.kvList=[]),t.kvList.push({key:"",value:""})}function s(){var e={};t.kvList.forEach(function(t){t.key&&(e[t.key]=t.value)}),i.$setViewValue(e),u()}function u(){var e=!0;t.required&&!t.kvList.length&&(e=!1),i.$setValidity("kvMap",e)}var d=o.default;n.html(d),t.ngModelCtrl=i,t.removeKeyVal=a,t.addKeyVal=l,t.kvList=[],t.$watch("query",function(e,n){angular.equals(e,n)||i.$setViewValue(t.query)}),i.$render=function(){if(i.$viewValue){var e=i.$viewValue;t.kvList.length=0;for(var n in e)t.kvList.push({key:n,value:e[n]})}t.$watch("kvList",function(e,t){angular.equals(e,t)||s()},!0),u()},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{required:"=ngRequired",disabled:"=ngDisabled",requiredText:"=",keyText:"=",keyRequiredText:"=",valText:"=",valRequiredText:"="},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(40),o=r(a);n(5)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.types=t,n.$watch("query",function(e,t){angular.equals(e,t)||a.$setViewValue(n.query)}),a.$render=function(){n.query=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","types"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(41),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t){var n=function(n,r,i,a){var l=o.default;r.html(l),n.ruleNodeTypes=t,n.$watch("configuration",function(e,t){angular.equals(e,t)||a.$setViewValue(n.configuration)}),a.$render=function(){n.configuration=a.$viewValue},e(r.contents())(n)};return{restrict:"E",require:"^ngModel",scope:{},link:n}}i.$inject=["$compile","ruleNodeTypes"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(42),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(85),a=r(i),o=n(87),l=r(o),s=n(88),u=r(s);t.default=angular.module("thingsboard.ruleChain.config.transform",[]).directive("tbTransformationNodeChangeOriginatorConfig",a.default).directive("tbTransformationNodeScriptConfig",l.default).directive("tbTransformationNodeToEmailConfig",u.default).name},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e,t,n){var r=function(r,i,a,l){var s=o.default;i.html(s),r.$watch("configuration",function(e,t){angular.equals(e,t)||l.$setViewValue(r.configuration)}),l.$render=function(){r.configuration=l.$viewValue},r.testScript=function(e){var i=angular.copy(r.configuration.jsScript);n.testNodeScript(e,i,"update",t.instant("tb.rulenode.transformer")+"","Transform",["msg","metadata","msgType"],r.ruleNodeId).then(function(e){r.configuration.jsScript=e,l.$setDirty()})},e(i.contents())(r)};return{restrict:"E",require:"^ngModel",scope:{ruleNodeId:"="},link:r}}i.$inject=["$compile","$translate","ruleNodeScriptTest"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(43),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){var t=function(t,n,r,i){var a=o.default;n.html(a),t.$watch("configuration",function(e,n){angular.equals(e,n)||i.$setViewValue(t.configuration)}),i.$render=function(){t.configuration=i.$viewValue},e(n.contents())(t)};return{restrict:"E",require:"^ngModel",scope:{},link:t}}i.$inject=["$compile"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(44),o=r(a)},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0});var i=n(92),a=r(i),o=n(78),l=r(o),s=n(72),u=r(s),d=n(86),c=r(d),m=n(52),g=r(m),p=n(68),f=r(p),b=n(84),v=r(b),y=n(67),q=r(y),h=n(83),$=r(h),x=n(91),T=r(x);t.default=angular.module("thingsboard.ruleChain.config",[a.default,l.default,u.default,c.default,g.default]).directive("tbNodeEmptyConfig",f.default).directive("tbRelationsQueryConfig",v.default).directive("tbDeviceRelationsQueryConfig",q.default).directive("tbKvMapConfig",$.default).config(T.default).name},function(e,t){"use strict";function n(e){var t={tb:{rulenode:{"create-entity-if-not-exists":"Create new entity if not exists","entity-name-pattern":"Name pattern","entity-name-pattern-required":"Name pattern is required","entity-name-pattern-hint":"Name pattern, use ${metaKeyName} to substitute variables from metadata","entity-type-pattern":"Type pattern","entity-type-pattern-required":"Type pattern is required","entity-type-pattern-hint":"Type pattern, use ${metaKeyName} to substitute variables from metadata","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-name-pattern-hint":"Customer name pattern, use ${metaKeyName} to substitute variables from metadata","customer-cache-expiration-hint":"Specifies maximum time interval allowed to store found customer records. 0 value means that records will never expire.","customer-cache-expiration-required":"Customers cache expiration time is required.","customer-cache-expiration-range":"Customers cache expiration time should be greater than or equal to 0.","start-interval":"Start Interval","end-interval":"End Interval","start-interval-time-unit":"Start Interval Time Unit","end-interval-time-unit":"End Interval Time Unit","fetch-mode":"Fetch mode","time-unit-milliseconds":"Milliseconds","time-unit-seconds":"Seconds","time-unit-minutes":"Minutes","time-unit-hours":"Hours","time-unit-days":"Days","time-value-range":"Time value should be in a range from 1 to 2147483647'.","start-interval-value-required":"Start interval value is required.","end-interval-value-required":"End interval value is required.",filter:"Filter",switch:"Switch","message-type":"Message type","message-type-required":"Message type is required.","message-types-filter":"Message types filter","no-message-types-found":"No message types found","no-message-type-matching":"'{{messageType}}' not found.","create-new-message-type":"Create a new one!","message-types-required":"Message types are required.","client-attributes":"Client attributes","shared-attributes":"Shared attributes","server-attributes":"Server attributes","latest-timeseries":"Latest timeseries","relations-query":"Relations query","device-relations-query":"Device relations query","max-relation-level":"Max relation level","unlimited-level":"Unlimited level","latest-telemetry":"Latest telemetry","attr-mapping":"Attributes mapping","source-attribute":"Source attribute","source-attribute-required":"Source attribute is required.","source-telemetry":"Source telemetry","source-telemetry-required":"Source telemetry is required.","target-attribute":"Target attribute","target-attribute-required":"Target attribute is required.","attr-mapping-required":"At least one attribute mapping should be specified.","fields-mapping":"Fields mapping","fields-mapping-required":"At least one field mapping should be specified.","source-field":"Source field","source-field-required":"Source field is required.","originator-source":"Originator source","originator-customer":"Customer","originator-tenant":"Tenant","originator-related":"Related","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.","min-period-seconds-message":"Only 1 second minimum period is allowed.",originator:"Originator","message-body":"Message body","message-metadata":"Message metadata",generate:"Generate","test-generator-function":"Test generator function",generator:"Generator","test-filter-function":"Test filter function","test-switch-function":"Test switch function","test-transformer-function":"Test transformer function",transformer:"Transformer","alarm-create-condition":"Alarm create condition","test-condition-function":"Test condition function","alarm-clear-condition":"Alarm clear condition","alarm-details-builder":"Alarm details builder","test-details-function":"Test details function","alarm-type":"Alarm type","alarm-type-required":"Alarm type is required.","alarm-severity":"Alarm severity","alarm-severity-required":"Alarm severity is required",propagate:"Propagate",condition:"Condition",details:"Details","to-string":"To string","test-to-string-function":"Test to string function","from-template":"From Template","from-template-required":"From Template is required","from-template-hint":"From address template, use ${metaKeyName} to substitute variables from metadata","to-template":"To Template","to-template-required":"To Template is required","mail-address-list-template-hint":"Comma separated address list, use ${metaKeyName} to substitute variables from metadata","cc-template":"Cc Template","bcc-template":"Bcc Template","subject-template":"Subject Template","subject-template-required":"Subject Template is required","subject-template-hint":"Mail subject template, use ${metaKeyName} to substitute variables from metadata","body-template":"Body Template","body-template-required":"Body Template is required","body-template-hint":"Mail body template, use ${metaKeyName} to substitute variables from metadata","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","endpoint-url-pattern-hint":"HTTP URL address pattern, use ${metaKeyName} to substitute variables from metadata","request-method":"Request method",headers:"Headers","headers-hint":"Use ${metaKeyName} in header/value fields to substitute variables from metadata",header:"Header","header-required":"Header is required",value:"Value","value-required":"Value is required","topic-pattern":"Topic pattern","topic-pattern-required":"Topic pattern is required","mqtt-topic-pattern-hint":"MQTT topic pattern, use ${metaKeyName} to substitute variables from metadata","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","topic-arn-pattern-hint":"Topic ARN pattern, use ${metaKeyName} to substitute variables from metadata","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","queue-url-pattern-hint":"Queue URL pattern, use ${metaKeyName} to substitute variables from metadata","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","message-attributes":"Message attributes","message-attributes-hint":"Use ${metaKeyName} in name/value fields to substitute variables from metadata","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","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","username-required":"Username is required.","password-required":"Password is required.","ca-cert":"CA certificate file *","private-key":"Private key file *",cert:"Certificate file *","no-file":"No file selected.","drop-file":"Drop a file or click to select a file to upload.","private-key-password":"Private key password","use-system-smtp-settings":"Use system SMTP settings","use-metadata-interval-patterns":"Use metadata interval patterns","start-interval-pattern":"Start interval pattern","end-interval-pattern":"End interval pattern","start-interval-pattern-required":"Start interval pattern is required","end-interval-pattern-required":"End interval pattern is required","start-interval-pattern-hint":"Start interval pattern, use ${metaKeyName} to substitute variables from metadata","end-interval-pattern-hint":"End interval pattern, use ${metaKeyName} to substitute variables from metadata","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","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."},"key-val":{key:"Key",value:"Value","remove-entry":"Remove entry","add-entry":"Add entry"}}};e.translations("en_US",t)}Object.defineProperty(t,"__esModule",{value:!0}),t.default=n},function(e,t,n){"use strict";function r(e){return e&&e.__esModule?e:{default:e}}function i(e){(0,o.default)(e)}i.$inject=["$translateProvider"],Object.defineProperty(t,"__esModule",{value:!0}),t.default=i;var a=n(90),o=r(a)},function(e,t){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=angular.module("thingsboard.ruleChain.config.types",[]).constant("ruleNodeTypes",{originatorSource:{CUSTOMER:{name:"tb.rulenode.originator-customer",value:"CUSTOMER"},TENANT:{name:"tb.rulenode.originator-tenant",value:"TENANT"},RELATED:{name:"tb.rulenode.originator-related",value:"RELATED"}},fetchModeType:["FIRST","LAST","ALL"],httpRequestType:["GET","POST","PUT","DELETE"],sqsQueueType:{STANDARD:{name:"tb.rulenode.sqs-queue-standard",value:"STANDARD"},FIFO:{name:"tb.rulenode.sqs-queue-fifo",value:"FIFO"}},timeUnit:{MILLISECONDS:{value:"MILLISECONDS",name:"tb.rulenode.time-unit-milliseconds"},SECONDS:{value:"SECONDS",name:"tb.rulenode.time-unit-seconds"},MINUTES:{value:"MINUTES",name:"tb.rulenode.time-unit-minutes"},HOURS:{value:"HOURS",name:"tb.rulenode.time-unit-hours"},DAYS:{value:"DAYS",name:"tb.rulenode.time-unit-days"}},mqttCredentialTypes:{anonymous:{value:"anonymous",name:"tb.rulenode.credentials-anonymous"},basic:{value:"basic",name:"tb.rulenode.credentials-basic"},"cert.PEM":{value:"cert.PEM",name:"tb.rulenode.credentials-pem"}}}).name}])); //# sourceMappingURL=rulenode-core-config.js.map \ No newline at end of file From 80af7ebf8d9e5dcb2fe8a9a3b867a2844bfcce97 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Sch=C3=B6nebeck?= <30472657+andyesys@users.noreply.github.com> Date: Thu, 20 Dec 2018 14:53:16 +0100 Subject: [PATCH 08/13] Update schema-entities.sql --- dao/src/main/resources/sql/schema-entities.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/resources/sql/schema-entities.sql b/dao/src/main/resources/sql/schema-entities.sql index 6d08611035..7a6ef7bb6d 100644 --- a/dao/src/main/resources/sql/schema-entities.sql +++ b/dao/src/main/resources/sql/schema-entities.sql @@ -72,7 +72,7 @@ CREATE TABLE IF NOT EXISTS attribute_kv ( long_v bigint, dbl_v double precision, last_update_ts bigint, - CONSTRAINT attribute_kv_unq_key UNIQUE (entity_type, entity_id, attribute_type, attribute_key) + CONSTRAINT attribute_kv_pkey PRIMARY KEY (entity_type, entity_id, attribute_type, attribute_key) ); CREATE TABLE IF NOT EXISTS component_descriptor ( @@ -148,7 +148,7 @@ CREATE TABLE IF NOT EXISTS relation ( relation_type_group varchar(255), relation_type varchar(255), additional_info varchar, - CONSTRAINT relation_unq_key UNIQUE (from_id, from_type, relation_type_group, relation_type, to_id, to_type) + CONSTRAINT relation_pkey PRIMARY KEY (from_id, from_type, relation_type_group, relation_type, to_id, to_type) ); CREATE TABLE IF NOT EXISTS tb_user ( From e0a272586e5511dc915c67e201810ae1a614a6f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Sch=C3=B6nebeck?= <30472657+andyesys@users.noreply.github.com> Date: Thu, 20 Dec 2018 14:54:44 +0100 Subject: [PATCH 09/13] Update schema-ts.sql --- dao/src/main/resources/sql/schema-ts.sql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dao/src/main/resources/sql/schema-ts.sql b/dao/src/main/resources/sql/schema-ts.sql index 53bc15acc3..821e297c19 100644 --- a/dao/src/main/resources/sql/schema-ts.sql +++ b/dao/src/main/resources/sql/schema-ts.sql @@ -23,7 +23,7 @@ CREATE TABLE IF NOT EXISTS ts_kv ( str_v varchar(10000000), long_v bigint, dbl_v double precision, - CONSTRAINT ts_kv_unq_key UNIQUE (entity_type, entity_id, key, ts) + CONSTRAINT ts_kv_pkey PRIMARY KEY (entity_type, entity_id, key, ts) ); CREATE TABLE IF NOT EXISTS ts_kv_latest ( @@ -35,5 +35,5 @@ CREATE TABLE IF NOT EXISTS ts_kv_latest ( str_v varchar(10000000), long_v bigint, dbl_v double precision, - CONSTRAINT ts_kv_latest_unq_key UNIQUE (entity_type, entity_id, key) + CONSTRAINT ts_kv_latest_pkey PRIMARY KEY (entity_type, entity_id, key) ); From adde20bd4f419aea73893a1038f2e08be8e05063 Mon Sep 17 00:00:00 2001 From: dvk2018 Date: Tue, 25 Dec 2018 17:15:57 +0500 Subject: [PATCH 10/13] Update russian locale. --- ui/src/app/locale/locale.constant-ru_RU.json | 1522 ++++++++++-------- 1 file changed, 867 insertions(+), 655 deletions(-) diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index eb9996d274..07ae86e5a0 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -22,8 +22,9 @@ "update": "Обновить", "remove": "Удалить", "search": "Поиск", + "clear-search": "Очистить", "assign": "Присвоить", - "unassign": "Отменить присвоение", + "unassign": "Отозвать", "share": "Поделиться", "make-private": "Закрыть для общего доступа", "apply": "Применить", @@ -43,6 +44,8 @@ "undo": "Откатить", "copy": "Копировать", "paste": "Вставить", + "copy-reference": "Копировать ссылку", + "paste-reference": "Вставить ссылку", "import": "Импортировать", "export": "Экспортировать", "share-via": "Поделиться в {{provider}}" @@ -83,168 +86,179 @@ "send-test-mail": "Отправить пробное письмо" }, "alarm": { - "alarm": "Alarm", - "alarms": "Alarms", - "select-alarm": "Select alarm", - "no-alarms-matching": "No alarms matching '{{entity}}' were found.", - "alarm-required": "Alarm is required", - "alarm-status": "Alarm status", + "alarm": "Оповещение", + "alarms": "Оповещения", + "select-alarm": "Выбрать оповещение", + "no-alarms-matching": "Оповещения '{{entity}}' не найдены.", + "alarm-required": "Оповещение обязательно", + "alarm-status": "Статус оповещения", "search-status": { - "ANY": "Any", - "ACTIVE": "Active", - "CLEARED": "Cleared", - "ACK": "Acknowledged", - "UNACK": "Unacknowledged" + "ANY": "Все", + "ACTIVE": "Активные", + "CLEARED": "Сброшенные", + "ACK": "Подтвержденные", + "UNACK": "Неподтвержденные" }, "display-status": { - "ACTIVE_UNACK": "Active Unacknowledged", - "ACTIVE_ACK": "Active Acknowledged", - "CLEARED_UNACK": "Cleared Unacknowledged", - "CLEARED_ACK": "Cleared Acknowledged" + "ACTIVE_UNACK": "Активные неподтвержденные", + "ACTIVE_ACK": "Активные подтвержденные", + "CLEARED_UNACK": "Сброшенные неподтвержденные", + "CLEARED_ACK": "Сброшенные подтвержденные" }, - "no-alarms-prompt": "No alarms found", - "created-time": "Created time", - "type": "Type", - "severity": "Severity", - "originator": "Originator", - "originator-type": "Originator type", - "details": "Details", - "status": "Status", - "alarm-details": "Alarm details", - "start-time": "Start time", - "end-time": "End time", - "ack-time": "Acknowledged time", - "clear-time": "Cleared time", - "severity-critical": "Critical", - "severity-major": "Major", - "severity-minor": "Minor", - "severity-warning": "Warning", - "severity-indeterminate": "Indeterminate", - "acknowledge": "Acknowledge", - "clear": "Clear", - "search": "Search alarms", - "selected-alarms": "{ count, plural, 1 {1 alarm} other {# alarms} } selected", - "no-data": "No data to display", - "polling-interval": "Alarms polling interval (sec)", - "polling-interval-required": "Alarms polling interval is required.", - "min-polling-interval-message": "At least 1 sec polling interval is allowed.", - "aknowledge-alarms-title": "Acknowledge { count, plural, 1 {1 alarm} other {# alarms} }", - "aknowledge-alarms-text": "Are you sure you want to acknowledge { count, plural, 1 {1 alarm} other {# alarms} }?", - "clear-alarms-title": "Clear { count, plural, 1 {1 alarm} other {# alarms} }", - "clear-alarms-text": "Are you sure you want to clear { count, plural, 1 {1 alarm} other {# alarms} }?" + "no-alarms-prompt": "Оповещения отсутствуют", + "created-time": "Время создания", + "type": "Тип", + "severity": "Уровень", + "originator": "Инициатор", + "originator-type": "Тип инициатора", + "details": "Подробности", + "status": "Статус", + "alarm-details": "Подробности об оповещении", + "start-time": "Время начала", + "end-time": "Время окончания", + "ack-time": "Время подтверждения", + "clear-time": "Время сброса", + "severity-critical": "Критический", + "severity-major": "Основной", + "severity-minor": "Второстепенный", + "severity-warning": "Предупреждение", + "severity-indeterminate": "Неопределенный", + "acknowledge": "Подтвердить", + "clear": "Сбросить", + "search": "Поиск оповещений", + "selected-alarms": "Выбрано { count, plural, 1 {1 оповещение} few {# оповещения} other {# оповещений} }", + "no-data": "Нет данных для отображения", + "polling-interval": "Интервал опроса оповещений (сек)", + "polling-interval-required": "Интервал опроса оповещений обязателен.", + "min-polling-interval-message": "Минимальный интервал опроса оповещений 1 секунда.", + "aknowledge-alarms-title": "Подтвердить { count, plural, 1 {1 оповещение} other {# оповещений} }", + "aknowledge-alarms-text": "Вы точно хотите подтвердить { count, plural, 1 {1 оповещение} other {# оповещений} }?", + "aknowledge-alarm-title": "Подтвердить оповещение", + "aknowledge-alarm-text": "Вы точно хотите подтвердить оповещение?", + "clear-alarms-title": "Сбросить { count, plural, 1 {1 оповещение} other {# оповещений} }", + "clear-alarms-text": "Вы точно хотите сбросить { count, plural, 1 {1 оповещение} other {# оповещений} }?", + "clear-alarm-title": "Сбросить оповещение", + "clear-alarm-text": "Вы точно хотите сбросить оповещение?", + "alarm-status-filter": "Фильтр оповещений" }, "alias": { - "add": "Add alias", - "edit": "Edit alias", - "name": "Alias name", - "name-required": "Alias name is required", - "duplicate-alias": "Alias with same name is already exists.", - "filter-type-single-entity": "Single entity", - "filter-type-entity-list": "Entity list", - "filter-type-entity-name": "Entity name", - "filter-type-state-entity": "Entity from dashboard state", - "filter-type-state-entity-description": "Entity taken from dashboard state parameters", - "filter-type-asset-type": "Asset type", - "filter-type-asset-type-description": "Assets of type '{{assetType}}'", - "filter-type-asset-type-and-name-description": "Assets of type '{{assetType}}' and with name starting with '{{prefix}}'", - "filter-type-device-type": "Device type", - "filter-type-device-type-description": "Devices of type '{{deviceType}}'", - "filter-type-device-type-and-name-description": "Devices of type '{{deviceType}}' and with name starting with '{{prefix}}'", - "filter-type-relations-query": "Relations query", - "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-asset-search-query": "Asset search query", - "filter-type-asset-search-query-description": "Assets with types {{assetTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", - "filter-type-device-search-query": "Device search query", - "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", - "entity-filter": "Entity filter", - "resolve-multiple": "Resolve as multiple entities", - "filter-type": "Filter type", - "filter-type-required": "Filter type is required.", - "entity-filter-no-entity-matched": "No entities matching specified filter were found.", - "no-entity-filter-specified": "No entity filter specified", - "root-state-entity": "Use dashboard state entity as root", - "root-entity": "Root entity", - "state-entity-parameter-name": "State entity parameter name", - "default-state-entity": "Default state entity", - "default-entity-parameter-name": "By default", - "max-relation-level": "Max relation level", - "unlimited-level": "Unlimited level", - "state-entity": "Dashboard state entity", - "all-entities": "All entities", - "any-relation": "any" + "add": "Добавить псевдоним", + "edit": "Редактировать псевдоним", + "name": "Псевдоним", + "name-required": "Псевдоним обязателен", + "duplicate-alias": "Такой псевдоним уже существует.", + "filter-type-single-entity": "Отдельный объект", + "filter-type-entity-list": "Список объектов", + "filter-type-entity-name": "Название объекта", + "filter-type-state-entity": "Объект, полученный из дашборда", + "filter-type-state-entity-description": "Объект, полученный из параметров дашборда", + "filter-type-asset-type": "Тип актива", + "filter-type-asset-type-description": "Активы типа '{{assetType}}'", + "filter-type-asset-type-and-name-description": "Активы типа '{{assetType}}' и названием, начинающимся с '{{prefix}}'", + "filter-type-device-type": "Тип устройства", + "filter-type-device-type-description": "Устройства типа '{{deviceType}}'", + "filter-type-device-type-and-name-description": "Устройства типа '{{deviceType}}' и названием, начинающимся с '{{prefix}}'", + "filter-type-entity-view-type": "Тип Представления Объекта", + "filter-type-entity-view-type-description": "Представления Объекта типа '{{entityView}}'", + "filter-type-entity-view-type-and-name-description": "Представления Объекта типа '{{entityView}}' и названием, начинающимся с '{{prefix}}'", + "filter-type-relations-query": "Запрос по типу отношений", + "filter-type-relations-query-description": "{{entities}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", + "filter-type-asset-search-query": "Поисковый запрос по активам", + "filter-type-asset-search-query-description": "Активы типа {{assetTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", + "filter-type-device-search-query": "Поисковый запрос по устройствам", + "filter-type-device-search-query-description": "Устройства типа {{deviceTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", + "filter-type-entity-view-search-query": "Поисковый запрос по представлениям объектов", + "filter-type-entity-view-search-query-description": "Представления объектов типа {{entityViewTypes}}, имеющие отношение типа {{relationType}} {{direction}} {{rootEntity}}", + "entity-filter": "Фильтр объектов", + "resolve-multiple": "Принять как несколько объектов", + "filter-type": "Тип фильтра", + "filter-type-required": "Тип фильтра обязателен.", + "entity-filter-no-entity-matched": "Объекты, соответствующие фильтру, не найдены.", + "no-entity-filter-specified": "Не указан фильтр объектов", + "root-state-entity": "Использовать объект, полученный из дашборда, как корневой", + "root-entity": "Корневой объект", + "state-entity-parameter-name": "Название объекта состояния", + "default-state-entity": "Объект состояния по умолчанию", + "default-entity-parameter-name": "По умолчанию", + "max-relation-level": "Максимальная глубина отношений", + "unlimited-level": "Неограниченная глубина", + "state-entity": "Объект состояния дашборда", + "all-entities": "Все объекты", + "any-relation": "не указано" }, "asset": { - "asset": "Asset", - "assets": "Assets", - "management": "Asset management", - "view-assets": "View Assets", - "add": "Add Asset", - "assign-to-customer": "Assign to customer", - "assign-asset-to-customer": "Assign Asset(s) To Customer", - "assign-asset-to-customer-text": "Please select the assets to assign to the customer", - "no-assets-text": "No assets found", - "assign-to-customer-text": "Please select the customer to assign the asset(s)", - "public": "Public", - "assignedToCustomer": "Assigned to customer", - "make-public": "Make asset public", - "make-private": "Make asset private", - "unassign-from-customer": "Unassign from customer", - "delete": "Delete asset", - "asset-public": "Asset is public", - "asset-type": "Asset type", - "asset-type-required": "Asset type is required.", - "select-asset-type": "Select asset type", - "enter-asset-type": "Enter asset type", - "any-asset": "Any asset", - "no-asset-types-matching": "No asset types matching '{{entitySubtype}}' were found.", - "asset-type-list-empty": "No asset types selected.", - "asset-types": "Asset types", - "name": "Name", - "name-required": "Name is required.", - "description": "Description", - "type": "Type", - "type-required": "Type is required.", - "details": "Details", - "events": "Events", - "add-asset-text": "Add new asset", - "asset-details": "Asset details", - "assign-assets": "Assign assets", - "assign-assets-text": "Assign { count, plural, 1 {1 asset} other {# assets} } to customer", - "delete-assets": "Delete assets", - "unassign-assets": "Unassign assets", - "unassign-assets-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from customer", - "assign-new-asset": "Assign new asset", - "delete-asset-title": "Are you sure you want to delete the asset '{{assetName}}'?", - "delete-asset-text": "Be careful, after the confirmation the asset and all related data will become unrecoverable.", - "delete-assets-title": "Are you sure you want to delete { count, plural, 1 {1 asset} other {# assets} }?", - "delete-assets-action-title": "Delete { count, plural, 1 {1 asset} other {# assets} }", - "delete-assets-text": "Be careful, after the confirmation all selected assets will be removed and all related data will become unrecoverable.", - "make-public-asset-title": "Are you sure you want to make the asset '{{assetName}}' public?", - "make-public-asset-text": "After the confirmation the asset and all its data will be made public and accessible by others.", - "make-private-asset-title": "Are you sure you want to make the asset '{{assetName}}' private?", - "make-private-asset-text": "After the confirmation the asset and all its data will be made private and won't be accessible by others.", - "unassign-asset-title": "Are you sure you want to unassign the asset '{{assetName}}'?", - "unassign-asset-text": "After the confirmation the asset will be unassigned and won't be accessible by the customer.", - "unassign-asset": "Unassign asset", - "unassign-assets-title": "Are you sure you want to unassign { count, plural, 1 {1 asset} other {# assets} }?", - "unassign-assets-text": "After the confirmation all selected assets will be unassigned and won't be accessible by the customer.", - "copyId": "Copy asset Id", - "idCopiedMessage": "Asset Id has been copied to clipboard", - "select-asset": "Select asset", - "no-assets-matching": "No assets matching '{{entity}}' were found.", - "asset-required": "Asset is required", - "name-starts-with": "Asset name starts with" + "asset": "Актив", + "assets": "Активы", + "management": "Управление активами", + "view-assets": "Просмотреть активы", + "add": "Добавить актив", + "assign-to-customer": "Присвоить клиенту", + "assign-asset-to-customer": "Присвоить актив(ы) клиенту", + "assign-asset-to-customer-text": "Пожалуйста, выберите активы, которые нужно присвоить объекту", + "no-assets-text": "Активы не найдены", + "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно присвоить актив(ы)", + "public": "Общедоступные", + "assignedToCustomer": "Присвоить клиенту", + "make-public": "Открыть общий доступ к активу", + "make-private": "Закрыть общий доступ к активу", + "unassign-from-customer": "Отозвать у клиента", + "delete": "Удалить актив", + "asset-public": "Актив общедоступный", + "asset-type": "Тип актива", + "asset-type-required": "Тип актива обязателен.", + "select-asset-type": "Выберите тип актива", + "enter-asset-type": "Введите тип актива", + "any-asset": "Любой актив", + "no-asset-types-matching": "Активы типа '{{entitySubtype}}' не найдены.", + "asset-type-list-empty": "Типы активов не выбраны.", + "asset-types": "Типы активов", + "name": "Название", + "name-required": "Название обязательно.", + "description": "Описание", + "type": "Тип", + "type-required": "Тип обязателен.", + "details": "Подробности", + "events": "События", + "add-asset-text": "Добавить новый актив", + "asset-details": "Подробности об активе", + "assign-assets": "Присвоить активы", + "assign-assets-text": "Присвоить { count, plural, 1 {1 актив} few {# актива} other {# активов} } клиенту", + "delete-assets": "Удалить активы", + "unassign-assets": "Отозвать активы", + "unassign-assets-action-title": "Отозвать { count, plural, 1 {1 актив} few {# актива} other {# активов} } у клиента", + "assign-new-asset": "Присвоить новый актив", + "delete-asset-title": "Вы точно хотите удалить '{{assetName}}'?", + "delete-asset-text": "Внимание, после подтверждения актив и все связанные с ним данные будут безвозвратно удалены.", + "delete-assets-title": "Вы точно хотите удалить { count, plural, 1 {1 актив} few {# актива} other {# активов} }", + "delete-assets-action-title": "Удалить { count, plural, 1 {1 актив} few {# актива} other {# активов} }", + "delete-assets-text": "Внимание, после подтверждения выбранные активы и все связанные с ними данные будут безвозвратно удалены.", + "make-public-asset-title": "Вы точно хотите открыть общий доступ к активу '{{assetName}}'?", + "make-public-asset-text": "Внимание, после подтверждения актив и все связанные с ним данные станут общедоступными.", + "make-private-asset-title": "Вы точно хотите закрыть общий доступ к активу '{{assetName}}'?", + "make-private-asset-text": "После подтверждения актив и все связанные с ним данные будут закрыты для общего доступа", + "unassign-asset-title": "Вы точно хотите отозвать актив '{{assetName}}'?", + "unassign-asset-text": "После подтверждения актив будут отозван, и клиент потеряет к нему доступ.", + "unassign-asset": "Отозвать актив", + "unassign-assets-title": "Вы точно хотите отозвать { count, plural, 1 {1 актив} few {# актива} other {# активов} }?", + "unassign-assets-text": "После подтверждения активы будут отозваны, и клиент потеряет к ним доступ.", + "copyId": "Копировать ИД актива", + "idCopiedMessage": "ИД актива скопировано в буфер обмена", + "select-asset": "Выбрать активы", + "no-assets-matching": "Активы, соответствующие '{{entity}}', не найдены.", + "asset-required": "Актив обязателен", + "name-starts-with": "Название актива, начинающееся с" }, "attribute": { "attributes": "Атрибуты", "latest-telemetry": "Последняя телеметрия", - "attributes-scope": "Контекст атрибутов устройства", + "attributes-scope": "Контекст атрибутов объекта", "scope-latest-telemetry": "Последняя телеметрия", "scope-client": "Клиентские атрибуты", "scope-server": "Серверные атрибуты", "scope-shared": "Общие атрибуты", "add": "Добавить атрибут", "key": "Ключ", + "last-update-time": "Последнее обновление", "key-required": "Ключ атрибута обязателен.", "value": "Значение", "value-required": "Значение атрибута обязательно.", @@ -262,36 +276,41 @@ "selected-telemetry": "{ count, plural, 1 {Выбран} other {Выбраны} } { count, plural, 1 {1 параметр} few {# параметра} other {# параметров} } телеметрии" }, "audit-log": { - "audit": "Audit", - "audit-logs": "Audit Logs", - "timestamp": "Timestamp", - "entity-type": "Entity Type", - "entity-name": "Entity Name", - "user": "User", - "type": "Type", - "status": "Status", - "details": "Details", - "type-added": "Added", - "type-deleted": "Deleted", - "type-updated": "Updated", - "type-attributes-updated": "Attributes updated", - "type-attributes-deleted": "Attributes deleted", - "type-rpc-call": "RPC call", - "type-credentials-updated": "Credentials updated", - "type-assigned-to-customer": "Assigned to Customer", - "type-unassigned-from-customer": "Unassigned from Customer", - "type-activated": "Activated", - "type-suspended": "Suspended", - "type-credentials-read": "Credentials read", - "type-attributes-read": "Attributes read", - "status-success": "Success", - "status-failure": "Failure", - "audit-log-details": "Audit log details", - "no-audit-logs-prompt": "No logs found", - "action-data": "Action data", - "failure-details": "Failure details", - "search": "Search audit logs", - "clear-search": "Clear search" + "audit": "Аудит", + "audit-logs": "Логи аудита", + "timestamp": "Время", + "entity-type": "Тип объекта", + "entity-name": "Название объекта", + "user": "Пользователь", + "type": "Тип", + "status": "Статус", + "details": "Подробности", + "type-added": "Добавленный", + "type-deleted": "Удаленный", + "type-updated": "Обновленный", + "type-attributes-updated": "Обновлены атрибуты", + "type-attributes-deleted": "Удалены атрибуты", + "type-rpc-call": "RPC вызов", + "type-credentials-updated": "Обновлены учетные данные", + "type-assigned-to-customer": "Присвоен клиенту", + "type-unassigned-from-customer": "Отозван у клиента", + "type-activated": "Активирован", + "type-suspended": "Приостановлен", + "type-credentials-read": "Чтение учетные данных", + "type-attributes-read": "Чтение атрибутов", + "type-relation-add-or-update": "Обновлены отношения", + "type-relation-delete": "Удалены отношения", + "type-relations-delete": "Удалены все отношения", + "type-alarm-ack": "Подтвержден", + "type-alarm-clear": "Сброшен", + "status-success": "Успех", + "status-failure": "Сбой", + "audit-log-details": "Подробности аудит лога", + "no-audit-logs-prompt": "Логи не найдены", + "action-data": "Данные действия", + "failure-details": "Подробности сбоя", + "search": "Поиск аудит логов", + "clear-search": "Очистить поиск" }, "confirm-on-exit": { "message": "У вас есть несохраненные изменения. Вы точно хотите покинуть эту страницу?", @@ -319,17 +338,22 @@ }, "content-type": { "json": "Json", - "text": "Text", - "binary": "Binary (Base64)" + "text": "Текстовый", + "binary": "Бинарный (Base64)" }, "customer": { + "customer": "Клиент", "customers": "Клиенты", "management": "Управление клиентами", - "dashboard": "Дашборд клиентов", - "dashboards": "Дашборды клиентов", + "dashboard": "Дашборд клиента", + "dashboards": "Дашборды клиента", "devices": "Устройства клиента", + "entity-views": "Представления объектов клиента", + "assets": "Активы клиента", "public-dashboards": "Общедоступные дашборды", "public-devices": "Общедоступные устройства", + "public-assets": "Общедоступные активы", + "public-entity-views": "Общедоступные представления объектов", "add": "Добавить клиента", "delete": "Удалить клиента", "manage-customer-users": "Управление пользователями клиента", @@ -337,31 +361,33 @@ "manage-customer-dashboards": "Управление дашбордами клиента", "manage-public-devices": "Управление общедоступными устройствами", "manage-public-dashboards": "Управление общедоступными дашбордами", + "manage-customer-assets": "Управление активами клиента", + "manage-public-assets": "Управление общедоступными активами", "add-customer-text": "Добавить нового клиента", "no-customers-text": "Клиенты не найдены", "customer-details": "Подробности о клиенте", "delete-customer-title": "Вы точно хотите удалить клиента '{{customerTitle}}'?", - "delete-customer-text": "Внимание, после подтверждения клиент и вся связанная с ним информация будут безвозвратно утеряны.", - "delete-customers-title": "Вы точно хотите удалить { count, plural, one {1 клиента} other {# клиентов} }?", - "delete-customers-action-title": "Удалить { count, plural, one {1 клиента} other {# клиентов} } }", - "delete-customers-text": "Внимание, после подтверждения клиенты и вся связанная с ними информация будут безвозвратно утеряны.", + "delete-customer-text": "Внимание, после подтверждения клиент и все связанные с ним данные будут безвозвратно удалены.", + "delete-customers-title": "Вы точно хотите удалить { count, plural, 1 {1 клиент} few {# клиента} other {# клиентов} }?", + "delete-customers-action-title": "Удалить { count, plural, 1 {1 клиент} few {# клиента} other {# клиентов} }", + "delete-customers-text": "Внимание, после подтверждения выбранные клиенты и все связанные с ними данные будут безвозвратно удалены.", "manage-users": "Управление пользователями", - "manage-assets": "Manage assets", + "manage-assets": "Управление активами", "manage-devices": "Управление устройствами", "manage-dashboards": "Управление дашбордами", "title": "Имя", "title-required": "Название обязательно.", "description": "Описание", - "details": "Details", - "events": "Events", - "copyId": "Copy customer Id", - "idCopiedMessage": "Customer Id has been copied to clipboard", - "select-customer": "Select customer", - "no-customers-matching": "No customers matching '{{entity}}' were found.", - "customer-required": "Customer is required", - "select-default-customer": "Select default customer", - "default-customer": "Default customer", - "default-customer-required": "Default customer is required in order to debug dashboard on Tenant level" + "details": "Подробности", + "events": "События", + "copyId": "Копировать ИД клиента", + "idCopiedMessage": "ИД клиента скопирован в буфер обмена", + "select-customer": "Выбрать клиента", + "no-customers-matching": "Клиенты, соответствующие '{{entity}}', не найдены.", + "customer-required": "Клиент обязателен", + "select-default-customer": "Выбрать клиента по умолчанию", + "default-customer": "Клиент по умолчанию", + "default-customer-required": "Клиент по умолчанию обязателен для отладки дашборда на уровне на уровне Владельца" }, "datetime": { "date-from": "Дата с", @@ -379,9 +405,15 @@ "assign-dashboard-to-customer-text": "Пожалуйста, выберите дашборды, которые нужно прикрепить к клиенту", "assign-to-customer-text": "Пожалуйста, выберите клиента, к которому нужно прикрепить дашборд(ы)", "assign-to-customer": "Прикрепить к клиенту", - "unassign-from-customer": "Открепить от клиента", + "unassign-from-customer": "Отозвать у клиента", "make-public": "Открыть дашборд для общего доступа", "make-private": "Закрыть дашборд для общего доступа", + "manage-assigned-customers": "Управление назначенными клиентами", + "assigned-customers": "Назначенные клиенты", + "assign-to-customers": "Присвоить дашборд(ы) клиенту", + "assign-to-customers-text": "Пожалуйста, выбери клиентов, которым нужно присвоить дашборд(ы)", + "unassign-from-customers": "Отозвать дашборд(ы) у клиентов", + "unassign-from-customers-text": "Пожалуйста, выберите клиентов, у которых нужно отозвать дашборд(ы)", "no-dashboards-text": "Дашборды не найдены", "no-widgets": "Виджеты не сконфигурированы", "add-widget": "Добавить новый виджет", @@ -396,19 +428,20 @@ "add-dashboard-text": "Добавить новый дашборд", "assign-dashboards": "Прикрепить дашборды", "assign-new-dashboard": "Прикрепить новый дашборд", - "assign-dashboards-text": "Прикрепить { count, plural, 1 {1 дашборд} other {# дашборда} } к клиенту", + "assign-dashboards-text": "Прикрепить { count, plural, 1 {1 дашборд} few {# дашборда} other {# дашбордов} } к клиенту", + "unassign-dashboards-action-text": "Отозвать { count, plural, 1 {1 дашборд} few {# дашборда} other {# дашбордов} } у клиента", "delete-dashboards": "Удалить дашборды", - "unassign-dashboards": "Открепить дашборды", - "unassign-dashboards-action-title": "Открепить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} } от клиента", + "unassign-dashboards": "Отозвать дашборды", + "unassign-dashboards-action-title": "Отозвать { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} } у клиента", "delete-dashboard-title": "Вы точно хотите удалить дашборд '{{dashboardTitle}}'?", "delete-dashboard-text": "Внимание, после подтверждения дашборд и все связанные с ним данные будут безвозвратно утеряны.", "delete-dashboards-title": "Вы точно хотите удалить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }?", "delete-dashboards-action-title": "Удалить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }", "delete-dashboards-text": "Внимание, после подтверждения дашборды и все связанные с ними данные будут безвозвратно утеряны.", - "unassign-dashboard-title": "Вы точно хотите открепить дашборд '{{dashboardTitle}}'?", + "unassign-dashboard-title": "Вы точно хотите отозвать дашборд '{{dashboardTitle}}'?", "unassign-dashboard-text": "После подтверждения дашборд не будет доступен клиенту.", - "unassign-dashboard": "Открепить дашборд", - "unassign-dashboards-title": "Вы точно хотите открепить { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }?", + "unassign-dashboard": "Отозвать дашборд", + "unassign-dashboards-title": "Вы точно хотите отозвать { count, plural, one {1 дашборд} few {# дашборда} other {# дашбордов} }?", "unassign-dashboards-text": "После подтверждения выбранные дашборды не будут доступны клиенту.", "public-dashboard-title": "Теперь дашборд общедоступный", "public-dashboard-text": "Теперь ваш дашборд {{dashboardTitle}} доступен всем по ссылке:", @@ -445,9 +478,17 @@ "vertical-margin-required": "Величина вертикального отступа обязательна.", "min-vertical-margin-message": "Минимальная величина вертикального отступа - 0.", "max-vertical-margin-message": "Максимальная величина вертикального отступа - 50.", + "autofill-height": "Автозаполнение по высоте", + "mobile-layout": "Настройки мобильного режима", + "mobile-row-height": "Высота строки в мобильном режиме, px", + "mobile-row-height-required": "Высота строки в мобильном режиме обязательна.", + "min-mobile-row-height-message": "Минимальная высота строки в мобильном режиме составляет 5 px.", + "max-mobile-row-height-message": "Максимальная высота строки в мобильном режиме составляет 200 px.", "display-title": "Показать название дашборда", + "toolbar-always-open": "Отображать панель инструментов", "title-color": "Цвет названия", - "display-device-selection": "Показать выборку устройств", + "display-dashboards-selection": "Отображать выборку дашбордов", + "display-entities-selection": "Отображать выбору объектов", "display-dashboard-timewindow": "Показать временное окно", "display-dashboard-export": "Показать экспорт", "import": "Импортировать дашборд", @@ -456,66 +497,74 @@ "create-new-dashboard": "Создать новый дашборд", "dashboard-file": "Файл дашборда", "invalid-dashboard-file-error": "Не удалось импортировать дашборд: неизвестная схема данных дашборда.", - "dashboard-import-missing-aliases-title": "Конфигурировать псевдонимы импортированного дашборда", + "dashboard-import-missing-aliases-title": "Настроить псевдонимы импортированного дашборда", "create-new-widget": "Создать новый виджет", - "import-widget": "Импортировать новый виджет", - "widget-file": "Файл виджета", - "invalid-widget-file-error": "Не удалось импортировать виджет: неизвестная схема данных виджета.", - "widget-import-missing-aliases-title": "Конфигурировать псевдонимы импортированного виджета", - "open-toolbar": "Открыть панель инструментов", + "import-widget": "Импортировать виджет", + "widget-file": "Виджет-файл", + "invalid-widget-file-error": "Не удалось импортировать виджет: неправильный формат данных.", + "widget-import-missing-aliases-title": "Настроить псевдонимы, которые использует импортированный виджет", + "open-toolbar": "Открыть панель инструментов дашборда", "close-toolbar": "Закрыть панель инструментов", - "configuration-error": "Ошибка конфигурирования", - "alias-resolution-error-title": "Ошибка конфигурирования псевдонимов дашборда", - "invalid-aliases-config": "Не удалось найти устройства, соответствующие фильтру псевдонимов.
Пожалуйста, свяжитесь с администратором для устранения этой проблемы.", + "configuration-error": "Ошибка в настройках", + "alias-resolution-error-title": "Ошибка в настройках псевдонимов дашборда", + "invalid-aliases-config": "Не удалось найти устройство, соответствующее фильтру псевдонимов.
Пожалуйста, обратитесь к администратору для устранения неполадки.", "select-devices": "Выберите устройства", - "assignedToCustomer": "Прикреплен к клиенту", - "public": "Общедоступный", - "public-link": "Общедоступная ссылка", - "copy-public-link": "Скопировать общедоступную ссылку", - "public-link-copied-message": "Общедоступная ссылка на дашборд скопирована в буфер обмена", - "manage-states": "Manage dashboard states", - "states": "Dashboard states", - "search-states": "Search dashboard states", - "selected-states": "{ count, plural, 1 {1 dashboard state} other {# dashboard states} } selected", - "edit-state": "Edit dashboard state", - "delete-state": "Delete dashboard state", - "add-state": "Add dashboard state", - "state": "Dashboard state", - "state-name": "Name", - "state-name-required": "Dashboard state name is required.", - "state-id": "State Id", - "state-id-required": "Dashboard state id is required.", - "state-id-exists": "Dashboard state with the same id is already exists.", - "is-root-state": "Root state", - "delete-state-title": "Delete dashboard state", - "delete-state-text": "Are you sure you want delete dashboard state with name '{{stateName}}'?", - "show-details": "Show details", - "hide-details": "Hide details", - "select-state": "Select target state", - "state-controller": "State controller" + "assignedToCustomer": "Присвоенные клиенту", + "assignedToCustomers": "Присвоенные клиентам", + "public": "Публичный", + "public-link": "Публичная ссылка", + "copy-public-link": "Копировать публичную ссылку", + "public-link-copied-message": "Публичная ссылка на дашборд скопирована в буфер обмена.", + "manage-states": "Управление состоянием дашборда", + "states": "Состояния дашборда", + "search-states": "Поиск состояния дашборда", + "selected-states": "Выбрано { count, plural, 1 {1 состояние} few {# состояния} other {# состояний} } дашборда", + "edit-state": "Изменить состояние дашборда", + "delete-state": "Удалить состояние дашборда", + "add-state": "Добавить состояние дашборда", + "state": "Состояние дашборда", + "state-name": "Название", + "state-name-required": "Название состояния дашборда обязательно.", + "state-id": "ИД состояния", + "state-id-required": "ИД состояния дашборда обязателен.", + "state-id-exists": "Состояния дашборда с таким именем уже существует.", + "is-root-state": "Корневое состояние", + "delete-state-title": "Удалить состояние дашборда", + "delete-state-text": "Вы точно хотите удалить состояние дашборда '{{stateName}}'?", + "show-details": "Показать подробности", + "hide-details": "Скрыть подробности", + "select-state": "Выбрать состояние", + "state-controller": "Контроллер состояния" }, "datakey": { "settings": "Настройки", "advanced": "Дополнительно", "label": "Метка", "color": "Цвет", - "units": "Special symbol to show next to value", - "decimals": "Number of digits after floating point", + "units": "Укажите символы, которые нужно указывать после значения", + "decimals": "Число знаков после запятой", "data-generation-func": "Функция генерации данных", "use-data-post-processing-func": "Использовать функцию пост-обработки данных", "configuration": "Конфигурация ключа данных", - "timeseries": "Выборка по времени", + "timeseries": "Телеметрия", "attributes": "Атрибуты", - "timeseries-required": "Выборка по времени обязательна.", - "timeseries-or-attributes-required": "Выборка по времени/атрибуты обязательны.", - "maximum-timeseries-or-attributes": "Maximum { count, plural, 1 {1 timeseries/attribute is allowed.} other {# timeseries/attributes are allowed} }", - "alarm-fields-required": "Alarm fields are required.", + "alarm": "Параметры оповещения", + "timeseries-required": "Телеметрия объекта обязательна.", + "timeseries-or-attributes-required": "Телеметрия/атрибуты обязательны.", + "maximum-timeseries-or-attributes": "Максимальное количество параметров телеметрии или атрибутов равно {{count}}", + "alarm-fields-required": "Параметры оповещения обязательны.", "function-types": "Тип функции", "function-types-required": "Тип функции обязателен.", - "maximum-function-types": "Maximum { count, plural, 1 {1 function type is allowed.} other {# function types are allowed} }" + "maximum-function-types": "Максимальное количество типов функции равно {{count}}" + "time-description": "время текущего значения;", + "value-description": "текущее значение;", + "prev-value-description": "результат предыдущего вызова функции;", + "time-prev-description": "время предыдущего значения;", + "prev-orig-value-description": "исходное предыдущее значение;" }, "datasource": { "type": "Тип источника данных", + "name": "Название", "add-datasource-prompt": "Пожалуйста, добавьте источник данных" }, "details": { @@ -537,7 +586,7 @@ "create-new-alias": "Создать новый!", "create-new-key": "Создать новый!", "duplicate-alias-error": "Найден дублирующийся псевдоним '{{alias}}'.
В рамках дашборда псевдонимы устройств должны быть уникальными.", - "configure-alias": "Конфигурировать '{{alias}}' псевдоним", + "configure-alias": "Настроить '{{alias}}' псевдоним", "no-devices-matching": "Устройство '{{entity}}' не найдено.", "alias": "Псевдоним", "alias-required": "Псевдоним устройства обязателен.", @@ -565,9 +614,9 @@ "assign-devices": "Присвоить устройство", "assign-devices-text": "Присвоить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } клиенту", "delete-devices": "Удалить устройства", - "unassign-from-customer": "Отменить присвоение клиенту", - "unassign-devices": "Отменить присвоение устройств", - "unassign-devices-action-title": "Отменить присвоение { count, plural, one {1 устройства} few {# устройств} other {# устройств} } клиенту", + "unassign-from-customer": "Отозвать у клиенту", + "unassign-devices": "Отозвать устройства", + "unassign-devices-action-title": "Отозвать у клиента { count, plural, one {1 устройство} few {# устройства} other {# устройств} }", "assign-new-device": "Присвоить новое устройство", "make-public-device-title": "Вы точно хотите открыть общий доступ к устройству '{{deviceName}}'?", "make-public-device-text": "После подтверждения устройство и все связанные с ним данные будут общедоступными.", @@ -579,10 +628,10 @@ "delete-devices-title": "Вы точно хотите удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} }?", "delete-devices-action-title": "Удалить { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }", "delete-devices-text": "Внимание, после подтверждения выбранные устройства и все связанные с ними данные будут безвозвратно утеряны..", - "unassign-device-title": "Вы точно хотите отменить присвоение устройства '{{deviceName}}'?", + "unassign-device-title": "Вы точно хотите отозвать устройство '{{deviceName}}'?", "unassign-device-text": "После подтверждения устройство будет недоступно клиенту.", - "unassign-device": "Отменить присвоение устройства", - "unassign-devices-title": "Вы точно хотите отменить присвоение { count, plural, one {1 устройство} few {# устройства} other {# устройств} } }?", + "unassign-device": "Отозвать устройство", + "unassign-devices-title": "Вы точно хотите отозвать { count, plural, one {1 устройство} few {# устройства} other {# устройств} }?", "unassign-devices-text": "После подтверждения выбранные устройства будут недоступны клиенту.", "device-credentials": "Учетные данные устройства", "credentials-type": "Тип учетных данных", @@ -593,6 +642,14 @@ "rsa-key-required": "Открытый ключ RSA обязателен.", "secret": "Секрет", "secret-required": "Секрет обязателен.", + "device-type": "Тип устройства", + "device-type-required": "Тип устройства обязатеен.", + "select-device-type": "Выберите тип устройства", + "enter-device-type": "Введите тип устройства", + "any-device": "Любое устройство", + "no-device-types-matching": "Тип устройства, соответствующий '{{entitySubtype}}', не найден.", + "device-type-list-empty": "Не выбран тип устройства.", + "device-types": "Типы устройств", "name": "Название", "name-required": "Название обязательно.", "description": "Описание", @@ -608,6 +665,7 @@ "is-gateway": "Гейтвей", "public": "Общедоступный", "device-public": "Устройство общедоступно" + "select-device": "Выбрать устройство" }, "dialog": { "close": "Закрыть диалог" @@ -618,100 +676,200 @@ "unknown-error": "Неизвестная ошибка" }, "entity": { - "entity": "Entity", - "entities": "Entities", - "aliases": "Entity aliases", - "entity-alias": "Entity alias", - "unable-delete-entity-alias-title": "Unable to delete entity alias", - "unable-delete-entity-alias-text": "Entity alias '{{entityAlias}}' can't be deleted as it used by the following widget(s):
{{widgetsList}}", - "duplicate-alias-error": "Duplicate alias found '{{alias}}'.
Entity aliases must be unique whithin the dashboard.", - "missing-entity-filter-error": "Filter is missing for alias '{{alias}}'.", - "configure-alias": "Configure '{{alias}}' alias", - "alias": "Alias", - "alias-required": "Entity alias is required.", - "remove-alias": "Remove entity alias", - "add-alias": "Add entity alias", - "entity-list": "Entity list", - "entity-type": "Entity type", - "entity-types": "Entity types", - "entity-type-list": "Entity type list", - "any-entity": "Any entity", - "enter-entity-type": "Enter entity type", - "no-entities-matching": "No entities matching '{{entity}}' were found.", - "no-entity-types-matching": "No entity types matching '{{entityType}}' were found.", - "name-starts-with": "Name starts with", - "use-entity-name-filter": "Use filter", - "entity-list-empty": "No entities selected.", - "entity-type-list-empty": "No entity types selected.", - "entity-name-filter-required": "Entity name filter is required.", - "entity-name-filter-no-entity-matched": "No entities starting with '{{entity}}' were found.", - "all-subtypes": "All", - "select-entities": "Select entities", - "no-aliases-found": "No aliases found.", - "no-alias-matching": "'{{alias}}' not found.", - "create-new-alias": "Create a new one!", - "key": "Key", - "key-name": "Key name", - "no-keys-found": "No keys found.", - "no-key-matching": "'{{key}}' not found.", - "create-new-key": "Create a new one!", - "type": "Type", - "type-required": "Entity type is required.", - "type-device": "Device", - "type-devices": "Devices", - "list-of-devices": "{ count, plural, 1 {One device} other {List of # devices} }", - "device-name-starts-with": "Devices whose names start with '{{prefix}}'", - "type-asset": "Asset", - "type-assets": "Assets", - "list-of-assets": "{ count, plural, 1 {One asset} other {List of # assets} }", - "asset-name-starts-with": "Assets whose names start with '{{prefix}}'", - "type-rule": "Rule", - "type-rules": "Rules", - "list-of-rules": "{ count, plural, 1 {One rule} other {List of # rules} }", - "rule-name-starts-with": "Rules whose names start with '{{prefix}}'", - "type-plugin": "Plugin", - "type-plugins": "Plugins", - "list-of-plugins": "{ count, plural, 1 {One plugin} other {List of # plugins} }", - "plugin-name-starts-with": "Plugins whose names start with '{{prefix}}'", - "type-tenant": "Tenant", - "type-tenants": "Tenants", - "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", - "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", - "type-customer": "Customer", - "type-customers": "Customers", - "list-of-customers": "{ count, plural, 1 {One customer} other {List of # customers} }", - "customer-name-starts-with": "Customers whose names start with '{{prefix}}'", - "type-user": "User", - "type-users": "Users", - "list-of-users": "{ count, plural, 1 {One user} other {List of # users} }", - "user-name-starts-with": "Users whose names start with '{{prefix}}'", - "type-dashboard": "Dashboard", - "type-dashboards": "Dashboards", - "list-of-dashboards": "{ count, plural, 1 {One dashboard} other {List of # dashboards} }", - "dashboard-name-starts-with": "Dashboards whose names start with '{{prefix}}'", - "type-alarm": "Alarm", - "type-alarms": "Alarms", - "list-of-alarms": "{ count, plural, 1 {One alarms} other {List of # alarms} }", - "alarm-name-starts-with": "Alarms whose names start with '{{prefix}}'", - "type-rulechain": "Rule chain", - "type-rulechains": "Rule chains", - "list-of-rulechains": "{ count, plural, 1 {One rule chain} other {List of # rule chains} }", - "rulechain-name-starts-with": "Rule chains whose names start with '{{prefix}}'", - "type-current-customer": "Current Customer", - "search": "Search entities", - "selected-entities": "{ count, plural, 1 {1 entity} other {# entities} } selected", - "entity-name": "Entity name", - "details": "Entity details", - "no-entities-prompt": "No entities found", - "no-data": "No data to display" + "entity": "Объект", + "entities": "Объекты", + "aliases": "Псевдонимы объекта", + "entity-alias": "Псевдоним объекта", + "unable-delete-entity-alias-title": "Не удалось удалить псевдоним объекта", + "unable-delete-entity-alias-text": "Псевдоним объекта '{{entityAlias}}' не может быть удален, так как используется следующим(и) виджетом(ами):
{{widgetsList}}", + "duplicate-alias-error": "Найден дубликат псевдонима '{{alias}}'.
В рамках одного дашборда псевдонимы объектов должны быть уникальными.", + "missing-entity-filter-error": "Отсутствует фильтр для псевдонима '{{alias}}'.", + "configure-alias": "Настроить псевдоним '{{alias}}'", + "alias": "Псевдоним", + "alias-required": "Псевдоним объекта обязателен.", + "remove-alias": "Убрать псевдоним объекта", + "add-alias": "Добавить псевдоним объекта", + "entity-list": "Список объектов", + "entity-type": "Тип объекта", + "entity-types": "Типы объекта", + "entity-type-list": "Список типов объекта", + "any-entity": "Любой объект", + "enter-entity-type": "Введите тип объекта", + "no-entities-matching": "Объекты, соответствующие '{{entity}}', не найдены.", + "no-entity-types-matching": "Типы объектов, соответствующие '{{entityType}}', не найдены.", + "name-starts-with": "Название, начинающееся с", + "use-entity-name-filter": "Использовать фильтр", + "entity-list-empty": "Не выбраны объекты.", + "entity-type-list-empty": "Не выбраны типы объекта.", + "entity-name-filter-required": "Фильтр по названию объекта обязателен.", + "entity-name-filter-no-entity-matched": "Объекты, чье название начинается с '{{entity}}', не найдены.", + "all-subtypes": "Все", + "select-entities": "Выберите объекты", + "no-aliases-found": "Псевдонимы не найдены.", + "no-alias-matching": "Псевдоним '{{alias}}' не найден.", + "create-new-alias": "Создать новый!", + "key": "Ключ", + "key-name": "Название ключа", + "no-keys-found": "Ключ не найден.", + "no-key-matching": "Ключ '{{key}}' не найден.", + "create-new-key": "Создать новый!", + "type": "Тип", + "type-required": "Тип объекта обязателен.", + "type-device": "Устройство", + "type-devices": "Устройства", + "list-of-devices": "{ count, plural, 1 {Одно устройство} other {Список из # устройств} }", + "device-name-starts-with": "Устройства, чьи название начинается с '{{prefix}}'", + "type-asset": "Актив", + "type-assets": "Активы", + "list-of-assets": "{ count, plural, 1 {Один актив} other {Список из # активов} }", + "asset-name-starts-with": "Активы, чьи название начинается с '{{prefix}}'", + "type-entity-view": "Представление Объекта", + "type-entity-views": "Представления Объекта", + "list-of-entity-views": "{ count, plural, 1 {Одно представление объекта} other {Список из # представлений объекта} }", + "entity-view-name-starts-with": "Представления Объекта, чьи название начинается с '{{prefix}}'", + "type-rule": "Правило", + "type-rules": "Правила", + "list-of-rules": "{ count, plural, 1 {Одно правило} other {Список из # правил} }", + "rule-name-starts-with": "Правила, чьи названия начинаются с '{{prefix}}'", + "type-plugin": "Плагин", + "type-plugins": "Плагины", + "list-of-plugins": "{ count, plural, 1 {Один плагин} other {Список из # плагинов} }", + "plugin-name-starts-with": "Плагины, чьи имена начинаются с '{{prefix}}'", + "type-tenant": "Владелец", + "type-tenants": "Владельцы", + "list-of-tenants": "{ count, plural, 1 {Один владелец} other {Список из # владельцев} }", + "tenant-name-starts-with": "Владельцы, чьи имена начинаются с '{{prefix}}'", + "type-customer": "Клиент", + "type-customers": "Клиенты", + "list-of-customers": "{ count, plural, 1 {Один клиент} other {Список из # клиентов} }", + "customer-name-starts-with": "Клиенты, чьи имена начинаются с '{{prefix}}'", + "type-user": "Пользователь", + "type-users": "Пользователи", + "list-of-users": "{ count, plural, 1 {Один пользователь} other {Список из # пользователей} }", + "user-name-starts-with": "Пользователи, чьи имена начинаются с '{{prefix}}'", + "type-dashboard": "Дашборд", + "type-dashboards": "Дашборды", + "list-of-dashboards": "{ count, plural, 1 {Один дашборд} other {Список из # дашбордов} }", + "dashboard-name-starts-with": "Дашборды, чьи названия начинаются с '{{prefix}}'", + "type-alarm": "Оповещение", + "type-alarms": "Оповещения", + "list-of-alarms": "{ count, plural, 1 {Одно оповещение} other {Список из # оповещений} }", + "alarm-name-starts-with": "Оповещения, чьи названия начинаются с '{{prefix}}'", + "type-rulechain": "Цепочка правил", + "type-rulechains": "Цепочки правил", + "list-of-rulechains": "{ count, plural, 1 {Одна цепочка правил} other {Список из # цепочек правил} }", + "rulechain-name-starts-with": "Цепочки правил, чьи названия начинаются с '{{prefix}}'", + "type-rulenode": "Правило", + "type-rulenodes": "Правила", + "list-of-rulenodes": "{ count, plural, 1 {Одно правило} other {Список из # правил} }", + "rulenode-name-starts-with": "Правила, чьи названия начинаются с '{{prefix}}'", + "type-current-customer": "Текущий клиент", + "search": "Поиск объектов", + "selected-entities": "Выбран(ы) { count, plural, 1 {1 объект} few {# объекта} other {# объектов} }", + "entity-name": "Название объекта", + "details": "Подробности об объекте", + "no-entities-prompt": "Объекты не найдены", + "no-data": "Нет данных для отображения", + "columns-to-display": "Отобразить следующие колонки" + }, + "entity-view": { + "entity-view": "Представление Объекта", + "entity-view-required": "Представление объекта обязательно.", + "entity-views": "Представления Объектов", + "management": "Управление представлениями объектов", + "view-entity-views": "Просмотр представлений объектов", + "entity-view-alias": "Псевдоним Представления Объекта", + "aliases": "Псевдонимы Представления Объекта", + "no-alias-matching": "Псевдоним '{{alias}}' не найден.", + "no-aliases-found": "Псевдонимы не найдены.", + "no-key-matching": "Ключ '{{key}}' не найден.", + "no-keys-found": "Ключи не найдены.", + "create-new-alias": "Создать новый!", + "create-new-key": "Создать новый!", + "duplicate-alias-error": "Найден дубликат псевдонима '{{alias}}'.
В рамках одного дашборда псевдонимы представлений объектов должны быть уникальными.", + "configure-alias": "Настроить псевдоним '{{alias}}'", + "no-entity-views-matching": "Объекты, соответствующие '{{entity}}', не найдены.", + "alias": "Псевдонимы", + "alias-required": "Псевдоним представления объекта обязателен.", + "remove-alias": "Убрать псевдоним представления объекта", + "add-alias": "Добавить псевдоним представления объекта", + "name-starts-with": "Представления объектов, чьи название начинается с", + "entity-view-list": "Список представлений объектов", + "use-entity-view-name-filter": "Использовать фильтр", + "entity-view-list-empty": "Не выбраны представления объектов.", + "entity-view-name-filter-required": "Для представлений объектов фильтр по названиям обязателен.", + "entity-view-name-filter-no-entity-view-matched": "Представление объектов, чьи название начинаются с '{{entityView}}', не найдены.", + "add": "Представление объекта", + "assign-to-customer": "Назначить клиенту", + "assign-entity-view-to-customer": "Назначить представление(я) объекта(ов) клиенту", + "assign-entity-view-to-customer-text": "Пожалуйста, выберите представления объектов, которые нужно назначить клиенту", + "no-entity-views-text": "Представления объектов не найдены", + "assign-to-customer-text": "Пожалуйста, выберите клиента, которому нужно назначить представления объектов", + "entity-view-details": "Подробности о представлении объекта", + "add-entity-view-text": "Добавить новое представление объекта", + "delete": "Удалить представление объекта", + "assign-entity-views": "Назначить представления объектов", + "assign-entity-views-text": "Назначить клиенту { count, plural, 1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", + "delete-entity-views": "Удалить представления объектов", + "unassign-from-customer": "Отозвать у клиента", + "unassign-entity-views": "Отозвать представления объектов", + "unassign-entity-views-action-title": "Отозвать у клиента { count, plural, 1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", + "assign-new-entity-view": "Назначит новое представление объекта", + "delete-entity-view-title": "Вы точно хотите удалить представление объекта '{{entityViewName}}'?", + "delete-entity-view-text": "Внимание, после подтверждения представление объекта и все связанные с ним данные будут безвозвратно удалены.", + "delete-entity-views-title": "Вы точно хотите удалить { count, plural, 1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }?", + "delete-entity-views-action-title": "Удалить { count, plural, 1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }", + "delete-entity-views-text": "Внимание, после подтверждения выбранные представления объектов и все связанные с ними данные будут безвозвратно удалены.", + "unassign-entity-view-title": "Вы точно хотите отозвать представление объекта '{{entityViewName}}'?", + "unassign-entity-view-text": "После подтверждение представление объекта будет недоступно клиенту.", + "unassign-entity-view": "Отозвать представление объекта", + "unassign-entity-views-title": "Вы точно хотите отозвать { count, plural, 1 {1 представление объекта} few {# представления объектов} other {# представлений объектов} }?", + "unassign-entity-views-text": "После подтверждение выбранные представления объектов будет недоступно клиенту.", + "entity-view-type": "Тип представления объекта", + "entity-view-type-required": "Тип представления объекта обязателен.", + "select-entity-view-type": "Выберите тип представления объекта", + "enter-entity-view-type": "Введите тип представления объекта", + "any-entity-view": "Любое представление объекта", + "no-entity-view-types-matching": "Типы представления объекта, соответствующие '{{entitySubtype}}', не найдены.", + "entity-view-type-list-empty": "Не выбраны типы представления объекта.", + "entity-view-types": "Типы представления объекта", + "name": "Название", + "name-required": "Название обязательно.", + "description": "Описание", + "events": "События", + "details": "Подробности", + "copyId": "Копировать ИД представление объекта", + "assignedToCustomer": "Назначенные клиенту", + "unable-entity-view-device-alias-title": "Не удалось удалить псевдоним представления объекта", + "unable-entity-view-device-alias-text": "Не удалось удалить псевдоним устройства '{{entityViewAlias}}', т.к. он используется следующими виджетами:
{{widgetsList}}", + "select-entity-view": "Выбрать представление объекта", + "make-public": "Открыть общий доступ к представлению объекта", + "start-date": "Дата начала", + "start-ts": "Время начала", + "end-date": "Дата окончания", + "end-ts": "Время окончания", + "date-limits": "Временной лимит", + "client-attributes": "Клиентские атрибуты", + "shared-attributes": "Общие атрибуты", + "server-attributes": "Серверные атрибуты", + "timeseries": "Телеметрия", + "client-attributes-placeholder": "Клиентские атрибуты", + "shared-attributes-placeholder": "Общие атрибуты", + "server-attributes-placeholder": "Серверные атрибуты", + "timeseries-placeholder": "Телеметрия", + "target-entity": "Целевой объект", + "attributes-propagation": "Пробросить атрибуты", + "attributes-propagation-hint": "Представление объекта автоматически копирует указанные атрибуты с Целевого Объекта каждый раз, когда вы сохраняете или обновляете это представление. В целях производительности атрибуты целевого объекта не пробрасываются в представление объекта на каждом их изменении. Вы можете включить автоматический проброс, настроив в вашей цепочке правило \"copy to view\" и соединив его с сообщениями типа \"Post attributes\" и \"Attributes Updated\".", + "timeseries-data": "Данные телеметрии", + "timeseries-data-hint": "Настроить ключи данных телеметрии целевого объекта, которые будут доступны представлению объекта. Эти данные только для чтения." }, "event": { "event-type": "Тип события", "type-error": "Ошибка", "type-lc-event": "Событие жизненного цикла", "type-stats": "Статистика", - "type-debug-rule-node": "Debug", - "type-debug-rule-chain": "Debug", + "type-debug-rule-node": "Отладка", + "type-debug-rule-chain": "Отладка", "no-events-prompt": "События не найдены", "error": "Ошибка", "alarm": "Аварийное оповещение", @@ -719,14 +877,14 @@ "server": "Сервер", "body": "Тело", "method": "Метод", - "type": "Type", - "entity": "Entity", - "message-id": "Message Id", - "message-type": "Message Type", - "data-type": "Data Type", - "relation-type": "Relation Type", - "metadata": "Metadata", - "data": "Data", + "type": "Тип", + "entity": "Объект", + "message-id": "ИД сообщения", + "message-type": "Тип сообщения", + "data-type": "Тип данных", + "relation-type": "Тип отношения", + "metadata": "Метаданные", + "data": "Данные", "event": "Событие", "status": "Статус", "success": "Успех", @@ -735,161 +893,161 @@ "errors-occurred": "Возникли ошибки" }, "extension": { - "extensions": "Extensions", - "selected-extensions": "{ count, plural, 1 {1 extension} other {# extensions} } selected", - "type": "Type", - "key": "Key", - "value": "Value", - "id": "Id", - "extension-id": "Extension id", - "extension-type": "Extension type", + "extensions": "Расширение", + "selected-extensions": "Выбрано { count, plural, 1 {1 расширение} few {# расширения} other {# расширений} }", + "type": "Тип", + "key": "Ключ", + "value": "Значение", + "id": "ИД", + "extension-id": "ИД расширения", + "extension-type": "Тип расширения", "transformer-json": "JSON *", - "unique-id-required": "Current extension id already exists.", - "delete": "Delete extension", - "add": "Add extension", - "edit": "Edit extension", - "delete-extension-title": "Are you sure you want to delete the extension '{{extensionId}}'?", - "delete-extension-text": "Be careful, after the confirmation the extension and all related data will become unrecoverable.", - "delete-extensions-title": "Are you sure you want to delete { count, plural, 1 {1 extension} other {# extensions} }?", - "delete-extensions-text": "Be careful, after the confirmation all selected extensions will be removed.", - "converters": "Converters", - "converter-id": "Converter id", - "configuration": "Configuration", - "converter-configurations": "Converter configurations", - "token": "Security token", - "add-converter": "Add converter", - "add-config": "Add converter configuration", - "device-name-expression": "Device name expression", - "device-type-expression": "Device type expression", - "custom": "Custom", + "unique-id-required": "Такое ИД расширения уже существует.", + "delete": "Удалить расширение", + "add": "Добавить расширение", + "edit": "Редактировать расширение", + "delete-extension-title": "Вы точно хотите удалить расширение '{{extensionId}}'?", + "delete-extension-text": "Внимание, после подтверждения расширение и все связанные с ним данные будут безвозвратно удалены.", + "delete-extensions-title": "Вы точно хотите удалить { count, plural, 1 {1 расширение} few {# расширения} other {# расширений} }?", + "delete-extensions-text": "Внимание, после подтверждения выбранные расширения будут удалены.", + "converters": "Конвертеры", + "converter-id": "ИД конвертера", + "configuration": "Конфигурация", + "converter-configurations": "Конфигурация конвертера", + "token": "Токен безопасности", + "add-converter": "Добавить конвертер", + "add-config": "Добавить конфигурацию конвертера", + "device-name-expression": "Маска названия устройства", + "device-type-expression": "Маска типа устройства", + "custom": "Пользовательский", "to-double": "To Double", - "transformer": "Transformer", - "json-required": "Transformer json is required.", - "json-parse": "Unable to parse transformer json.", - "attributes": "Attributes", - "add-attribute": "Add attribute", - "add-map": "Add mapping element", - "timeseries": "Timeseries", - "add-timeseries": "Add timeseries", - "field-required": "Field is required", - "brokers": "Brokers", - "add-broker": "Add broker", - "host": "Host", - "port": "Port", - "port-range": "Port should be in a range from 1 to 65535.", - "ssl": "Ssl", - "credentials": "Credentials", - "username": "Username", - "password": "Password", - "retry-interval": "Retry interval in milliseconds", - "anonymous": "Anonymous", - "basic": "Basic", + "transformer": "Преобразователь", + "json-required": "JSON преобразователя обязателен.", + "json-parse": "Не удалось распознать JSON преобразователя.", + "attributes": "Атрибуты", + "add-attribute": "Добавить атрибут", + "add-map": "Добавить элемент сопоставления", + "timeseries": "Телеметрия", + "add-timeseries": "Добавить параметр телеметрии", + "field-required": "Параметр обязателен", + "brokers": "Брокеры", + "add-broker": "Добавить брокер", + "host": "Хост", + "port": "Порт", + "port-range": "Значение порта лежит в диапазоне от 1 до 65535.", + "ssl": "SSL", + "credentials": "Учетные данные", + "username": "Имя пользователя", + "password": "Пароль", + "retry-interval": "Интервал повтора в миллисекундах", + "anonymous": "Анонимный", + "basic": "Общий", "pem": "PEM", - "ca-cert": "CA certificate file *", - "private-key": "Private key file *", - "cert": "Certificate file *", - "no-file": "No file selected.", - "drop-file": "Drop a file or click to select a file to upload.", - "mapping": "Mapping", - "topic-filter": "Topic filter", - "converter-type": "Converter type", - "converter-json": "Json", - "json-name-expression": "Device name json expression", - "topic-name-expression": "Device name topic expression", - "json-type-expression": "Device type json expression", - "topic-type-expression": "Device type topic expression", - "attribute-key-expression": "Attribute key expression", - "attr-json-key-expression": "Attribute key json expression", - "attr-topic-key-expression": "Attribute key topic expression", - "request-id-expression": "Request id expression", - "request-id-json-expression": "Request id json expression", - "request-id-topic-expression": "Request id topic expression", - "response-topic-expression": "Response topic expression", - "value-expression": "Value expression", - "topic": "Topic", - "timeout": "Timeout in milliseconds", - "converter-json-required": "Converter json is required.", - "converter-json-parse": "Unable to parse converter json.", - "filter-expression": "Filter expression", - "connect-requests": "Connect requests", - "add-connect-request": "Add connect request", - "disconnect-requests": "Disconnect requests", - "add-disconnect-request": "Add disconnect request", - "attribute-requests": "Attribute requests", - "add-attribute-request": "Add attribute request", - "attribute-updates": "Attribute updates", - "add-attribute-update": "Add attribute update", - "server-side-rpc": "Server side RPC", - "add-server-side-rpc-request": "Add server-side RPC request", - "device-name-filter": "Device name filter", - "attribute-filter": "Attribute filter", - "method-filter": "Method filter", - "request-topic-expression": "Request topic expression", - "response-timeout": "Response timeout in milliseconds", - "topic-expression": "Topic expression", - "client-scope": "Client scope", - "add-device": "Add device", - "opc-server": "Servers", - "opc-add-server": "Add server", - "opc-add-server-prompt": "Please add server", - "opc-application-name": "Application name", - "opc-application-uri": "Application uri", - "opc-scan-period-in-seconds": "Scan period in seconds", - "opc-security": "Security", - "opc-identity": "Identity", - "opc-keystore": "Keystore", - "opc-type": "Type", - "opc-keystore-type": "Type", - "opc-keystore-location": "Location *", - "opc-keystore-password": "Password", - "opc-keystore-alias": "Alias", - "opc-keystore-key-password": "Key password", - "opc-device-node-pattern": "Device node pattern", - "opc-device-name-pattern": "Device name pattern", - "modbus-server": "Servers/slaves", - "modbus-add-server": "Add server/slave", - "modbus-add-server-prompt": "Please add server/slave", - "modbus-transport": "Transport", - "modbus-port-name": "Serial port name", - "modbus-encoding": "Encoding", - "modbus-parity": "Parity", - "modbus-baudrate": "Baud rate", - "modbus-databits": "Data bits", - "modbus-stopbits": "Stop bits", - "modbus-databits-range": "Data bits should be in a range from 7 to 8.", - "modbus-stopbits-range": "Stop bits should be in a range from 1 to 2.", - "modbus-unit-id": "Unit ID", - "modbus-unit-id-range": "Unit ID should be in a range from 1 to 247.", - "modbus-device-name": "Device name", - "modbus-poll-period": "Poll period (ms)", - "modbus-attributes-poll-period": "Attributes poll period (ms)", - "modbus-timeseries-poll-period": "Timeseries poll period (ms)", - "modbus-poll-period-range": "Poll period should be positive value.", - "modbus-tag": "Tag", - "modbus-function": "Function", - "modbus-register-address": "Register address", - "modbus-register-address-range": "Register address should be in a range from 0 to 65535.", - "modbus-register-bit-index": "Bit index", - "modbus-register-bit-index-range": "Bit index should be in a range from 0 to 15.", - "modbus-register-count": "Register count", - "modbus-register-count-range": "Register count should be a positive value.", - "modbus-byte-order": "Byte order", + "ca-cert": "Файл CA сертификата *", + "private-key": "Файл приватного ключа *", + "cert": "Файл сертификата *", + "no-file": "Не выбран файл.", + "drop-file": "Перетяните файл или нажмите для выбора файла.", + "mapping": "Сопоставление", + "topic-filter": "Фильтр тем", + "converter-type": "Тип конвертера", + "converter-json": "JSON", + "json-name-expression": "JSON выражение для названия устройства", + "topic-name-expression": "Выражение для названия устройства в названии темы", + "json-type-expression": "JSON выражение для типа устройства", + "topic-type-expression": "Выражение для типа устройства в названии темы", + "attribute-key-expression": "Выражение для атрибута", + "attr-json-key-expression": "JSON выражение для атрибута", + "attr-topic-key-expression": "Выражение для атрибута в названии темы", + "request-id-expression": "Выражение для ИД запроса", + "request-id-json-expression": "JSON выражение для ИД запроса", + "request-id-topic-expression": "Выражение для ИД запроса в названии темы", + "response-topic-expression": "Выражение для темы ответов", + "value-expression": "Выражение для значения", + "topic": "Тема", + "timeout": "Таймаут в миллисекундах", + "converter-json-required": "JSON конвертер обязателен.", + "converter-json-parse": "Не удалось распознать JSON конвертера.", + "filter-expression": "Выражение для фильтрации", + "connect-requests": "Запросы о подключении устройства", + "add-connect-request": "Добавить запросы о подключении устройства", + "disconnect-requests": "Запросы об отсоединении устройства", + "add-disconnect-request": "Добавить запрос об отсоединении устройства", + "attribute-requests": "Запросы для атрибутов", + "add-attribute-request": "Добавить запрос для атрибутов", + "attribute-updates": "Обновление атрибутов", + "add-attribute-update": "Добавить обновление атрибутов", + "server-side-rpc": "Серверный RPC", + "add-server-side-rpc-request": "Добавить серверный RPC", + "device-name-filter": "Фильтр для названия устройства", + "attribute-filter": "Фильтр для атрибутов", + "method-filter": "Фильтр для процедур", + "request-topic-expression": "Выражение для темы запросов", + "response-timeout": "Время ожидания ответа в миллисекундах", + "topic-expression": "Выражение для названия темы", + "client-scope": "Клиентский", + "add-device": "Добавить устройство", + "opc-server": "Серверы", + "opc-add-server": "Добавить сервер", + "opc-add-server-prompt": "Пожалуйста, добавьте сервер", + "opc-application-name": "Название приложения", + "opc-application-uri": "URI приложения", + "opc-scan-period-in-seconds": "Частота сканирования в секундах", + "opc-security": "Безопасность", + "opc-identity": "Идентификация", + "opc-keystore": "Хранилище ключей", + "opc-type": "Тип", + "opc-keystore-type": "Тип", + "opc-keystore-location": "Расположение *", + "opc-keystore-password": "Пароль", + "opc-keystore-alias": "Псевдоним", + "opc-keystore-key-password": "Пароль для ключ", + "opc-device-node-pattern": "Паттерн OPC узла устройства", + "opc-device-name-pattern": "Паттерн названия устройства", + "modbus-server": "Серверы/ведомые устройства", + "modbus-add-server": "Добавить сервер/ведомое устройство", + "modbus-add-server-prompt": "Пожалуйста, добавить сервер/ведомое устройство", + "modbus-transport": "Транспорт", + "modbus-port-name": "Название последовательного порта", + "modbus-encoding": "Кодирование символов", + "modbus-parity": "Паритет", + "modbus-baudrate": "Скорость передачи", + "modbus-databits": "Биты данных", + "modbus-stopbits": "Стоп-биты", + "modbus-databits-range": "Параметр \"Биты данных\" может принимать значения 7 или 8.", + "modbus-stopbits-range": "Параметр \"Стоп-биты\" может принимать значения 1 или 2.", + "modbus-unit-id": "ИД устройства", + "modbus-unit-id-range": "ИД устройства должен быть в диапазоне от 1 до 247.", + "modbus-device-name": "Название устройства", + "modbus-poll-period": "Частота опроса (в миллисекундах)", + "modbus-attributes-poll-period": "Частота опроса для атрибутов (в миллисекундах)", + "modbus-timeseries-poll-period": "Частота опроса для телеметрии (в миллисекундах)", + "modbus-poll-period-range": "Значение параметра \"Частота опроса\" должно быть больше ноля.", + "modbus-tag": "Тег", + "modbus-function": "Modbus функция", + "modbus-register-address": "Адрес регистра", + "modbus-register-address-range": "Адрес регистра должен быть в диапазоне от 0 до 65535.", + "modbus-register-bit-index": "Номер бита", + "modbus-register-bit-index-range": "Номер бита должен быть в диапазоне от 0 до 15.", + "modbus-register-count": "Количество регистров", + "modbus-register-count-range": "Количество регистров должно быть больше ноля.", + "modbus-byte-order": "Порядок байтов", "sync": { - "status": "Status", - "sync": "Sync", - "not-sync": "Not sync", - "last-sync-time": "Last sync time", - "not-available": "Not available" + "status": "Статус", + "sync": "Синхронизирован", + "not-sync": "Не синхронизирован", + "last-sync-time": "Время последней синхронизации", + "not-available": "Не доступен" }, - "export-extensions-configuration": "Export extensions configuration", - "import-extensions-configuration": "Import extensions configuration", - "import-extensions": "Import extensions", - "import-extension": "Import extension", - "export-extension": "Export extension", - "file": "Extensions file", - "invalid-file-error": "Invalid extension file" + "export-extensions-configuration": "Экспортировать конфигурацию расширений", + "import-extensions-configuration": "Импортировать конфигурацию расширений", + "import-extensions": "Импортировать расширения", + "import-extension": "Импортировать расширение", + "export-extension": "Экспортировать расширение", + "file": "Файл расширений", + "invalid-file-error": "Не правильный формат файла" }, "fullscreen": { "expand": "Во весь экран", @@ -937,20 +1095,20 @@ "tidy": "Tidy" }, "key-val": { - "key": "Key", - "value": "Value", - "remove-entry": "Remove entry", - "add-entry": "Add entry", - "no-data": "No entries" + "key": "Ключ", + "value": "Значение", + "remove-entry": "Удалить элемент", + "add-entry": "Добавить элемент", + "no-data": "Элементы отсутствуют" }, "layout": { - "layout": "Layout", - "manage": "Manage layouts", - "settings": "Layout settings", - "color": "Color", - "main": "Main", - "right": "Right", - "select": "Select target layout" + "layout": "Макет", + "manage": "Управление макетами", + "settings": "Настройки макета", + "color": "Цвет", + "main": "Основной", + "right": "Правый", + "select": "Выбрать макет" }, "legend": { "position": "Расположение легенды", @@ -993,140 +1151,149 @@ "current-password": "Текущий пароль" }, "relation": { - "relations": "Relations", - "direction": "Direction", + "relations": "Отношения", + "direction": "Направления", "search-direction": { - "FROM": "From", - "TO": "To" + "FROM": "От", + "TO": "К" }, "direction-type": { - "FROM": "from", - "TO": "to" + "FROM": "от", + "TO": "к" }, - "from-relations": "Outbound relations", - "to-relations": "Inbound relations", - "selected-relations": "{ count, plural, 1 {1 relation} other {# relations} } selected", - "type": "Type", - "to-entity-type": "To entity type", - "to-entity-name": "To entity name", - "from-entity-type": "From entity type", - "from-entity-name": "From entity name", - "to-entity": "To entity", - "from-entity": "From entity", - "delete": "Delete relation", - "relation-type": "Relation type", - "relation-type-required": "Relation type is required.", - "any-relation-type": "Any type", - "add": "Add relation", - "edit": "Edit relation", - "delete-to-relation-title": "Are you sure you want to delete relation to the entity '{{entityName}}'?", - "delete-to-relation-text": "Be careful, after the confirmation the entity '{{entityName}}' will be unrelated from the current entity.", - "delete-to-relations-title": "Are you sure you want to delete { count, plural, 1 {1 relation} other {# relations} }?", - "delete-to-relations-text": "Be careful, after the confirmation all selected relations will be removed and corresponding entities will be unrelated from the current entity.", - "delete-from-relation-title": "Are you sure you want to delete relation from the entity '{{entityName}}'?", - "delete-from-relation-text": "Be careful, after the confirmation current entity will be unrelated from the entity '{{entityName}}'.", - "delete-from-relations-title": "Are you sure you want to delete { count, plural, 1 {1 relation} other {# relations} }?", - "delete-from-relations-text": "Be careful, after the confirmation all selected relations will be removed and current entity will be unrelated from the corresponding entities.", - "remove-relation-filter": "Remove relation filter", - "add-relation-filter": "Add relation filter", - "any-relation": "Any relation", - "relation-filters": "Relation filters", - "additional-info": "Additional info (JSON)", - "invalid-additional-info": "Unable to parse additional info json." + "from-relations": "Исходящие отношения", + "to-relations": "Входящие отношения", + "selected-relations": "Выбрано { count, plural, 1 {1 отношение} few {# отношения} other {# отношений} }", + "type": "Тип", + "to-entity-type": "К типу объекта", + "to-entity-name": "К объекта", + "from-entity-type": "От типа объекта", + "from-entity-name": "От объекта", + "to-entity": "К объекту", + "from-entity": "От объекта", + "delete": "Удалить отношение", + "relation-type": "Тип отношения", + "relation-type-required": "Тип отношения обязателен.", + "any-relation-type": "Любой тип", + "add": "Добавить отношение", + "edit": "Редактировать отношение", + "delete-to-relation-title": "Вы точно хотите удалить отношение, идущее к объекту '{{entityName}}'?", + "delete-to-relation-text": "Внимание, после подтверждения объект '{{entityName}}' будет отвязан от текущего объекта.", + "delete-to-relations-title": "Вы точно хотите удалить { count, plural, 1 {1 отношение} few {# отношения} other {# отношений} }?", + "delete-to-relations-text": "Внимание, после подтверждения выбранные объекты будут отвязаны от текущего объекта.", + "delete-from-relation-title": "Вы точно хотите удалить отношение, идущее от объекта '{{entityName}}'?", + "delete-from-relation-text": "Внимание, после подтверждения текущий объект будет отвязан от объекта '{{entityName}}'.", + "delete-from-relations-title": "Вы точно хотите удалить { count, plural, 1 {1 отношение} few {# отношения} other {# отношений} }?", + "delete-from-relations-text": "Внимание, после подтверждения выбранные объекты будут отвязаны от соответствующих объектов.", + "remove-relation-filter": "Удалить фильтр отношений", + "add-relation-filter": "Добавить фильтр отношений", + "any-relation": "Любое отношение", + "relation-filters": "Фильтры отношений", + "additional-info": "Дополнительная информация (JSON)", + "invalid-additional-info": "Не удалось распознать JSON с дополнительной информацией." }, "rulechain": { - "rulechain": "Rule chain", - "rulechains": "Rule chains", - "root": "Root", - "delete": "Delete rule chain", - "name": "Name", - "name-required": "Name is required.", - "description": "Description", - "add": "Add Rule Chain", - "set-root": "Make rule chain root", - "set-root-rulechain-title": "Are you sure you want to make the rule chain '{{ruleChainName}}' root?", - "set-root-rulechain-text": "After the confirmation the rule chain will become root and will handle all incoming transport messages.", - "delete-rulechain-title": "Are you sure you want to delete the rule chain '{{ruleChainName}}'?", - "delete-rulechain-text": "Be careful, after the confirmation the rule chain and all related data will become unrecoverable.", - "delete-rulechains-title": "Are you sure you want to delete { count, plural, 1 {1 rule chain} other {# rule chains} }?", - "delete-rulechains-action-title": "Delete { count, plural, 1 {1 rule chain} other {# rule chains} }", - "delete-rulechains-text": "Be careful, after the confirmation all selected rule chains will be removed and all related data will become unrecoverable.", - "add-rulechain-text": "Add new rule chain", - "no-rulechains-text": "No rule chains found", - "rulechain-details": "Rule chain details", - "details": "Details", - "events": "Events", - "system": "System", - "import": "Import rule chain", - "export": "Export rule chain", - "export-failed-error": "Unable to export rule chain: {{error}}", - "create-new-rulechain": "Create new rule chain", - "rulechain-file": "Rule chain file", - "invalid-rulechain-file-error": "Unable to import rule chain: Invalid rule chain data structure.", - "copyId": "Copy rule chain Id", - "idCopiedMessage": "Rule chain Id has been copied to clipboard", - "select-rulechain": "Select rule chain", - "no-rulechains-matching": "No rule chains matching '{{entity}}' were found.", - "rulechain-required": "Rule chain is required", - "management": "Rules management", - "debug-mode": "Debug mode" + "rulechain": "Цепочка правил", + "rulechains": "Цепочки правил", + "root": "Корневая", + "delete": "Удалить цепочку правил", + "name": "Названия", + "name-required": "Название необходимо.", + "description": "Описание", + "add": "Добавить цепочку правил", + "set-root": "Сделать цепочку корневой", + "set-root-rulechain-title": "Вы точно хотите сделать цепочку правил '{{ruleChainName}}' корневой?", + "set-root-rulechain-text": "После подтверждения цепочка правил станет корневой и будет обрабатывать все входящие сообщения.", + "delete-rulechain-title": "Вы точно хотите удалить цепочку правил '{{ruleChainName}}'?", + "delete-rulechain-text": "Внимание, после подтверждения цепочка правил и все связанные с ней данные будут безвозвратно удалены.", + "delete-rulechains-title": "Вы точно хотите удалить { count, plural, 1 {1 цепочку правил} few {# цепочки правил} other {# цепочек правил} }?", + "delete-rulechains-action-title": "Удалить { count, plural, 1 {1 цепочку правил} few {# цепочки правил} other {# цепочек правил} }", + "delete-rulechains-text": "Внимание, после подтверждения выбранные цепочки правил и все связанные с ними данные будут безвозвратно удалены.", + "add-rulechain-text": "Добавить новую цепочку правил", + "no-rulechains-text": "Цепочки правил не найдены", + "rulechain-details": "Подробности о цепочке правил", + "details": "Подробности", + "events": "События", + "system": "Системная", + "import": "Импортировать цепочку правил", + "export": "Экспортировать цепочку правил", + "export-failed-error": "Не удалось экспортировать цепочку правил: {{error}}", + "create-new-rulechain": "Создать новую цепочку правил", + "rulechain-file": "Файл цепочки правил", + "invalid-rulechain-file-error": "Не удалось импортировать цепочку правил: неправильный формат.", + "copyId": "Копировать ИД цепочки правил", + "idCopiedMessage": "ИД цепочки правил скопирован в буфер обмена", + "select-rulechain": "Выбрать цепочку правил", + "no-rulechains-matching": "Цепочки правил, соответствующие '{{entity}}', не найдены.", + "rulechain-required": "Цепочка правил обязательна", + "management": "Управление цепочками правил", + "debug-mode": "Режим отладки" }, "rulenode": { - "details": "Details", - "events": "Events", - "search": "Search nodes", - "open-node-library": "Open node library", - "add": "Add rule node", - "name": "Name", - "name-required": "Name is required.", - "type": "Type", - "description": "Description", - "delete": "Delete rule node", - "select-all-objects": "Select all nodes and connections", - "deselect-all-objects": "Deselect all nodes and connections", - "delete-selected-objects": "Delete selected nodes and connections", - "delete-selected": "Delete selected", - "select-all": "Select all", - "copy-selected": "Copy selected", - "deselect-all": "Deselect all", - "rulenode-details": "Rule node details", - "debug-mode": "Debug mode", - "configuration": "Configuration", - "link": "Link", - "link-details": "Rule node link details", - "add-link": "Add link", - "link-label": "Link label", - "link-label-required": "Link label is required.", - "custom-link-label": "Custom link label", - "custom-link-label-required": "Custom link label is required.", - "type-filter": "Filter", - "type-filter-details": "Filter incoming messages with configured conditions", - "type-enrichment": "Enrichment", - "type-enrichment-details": "Add additional information into Message Metadata", - "type-transformation": "Transformation", - "type-transformation-details": "Change Message payload and Metadata", - "type-action": "Action", - "type-action-details": "Perform special action", - "type-external": "External", - "type-external-details": "Interacts with external system", - "type-rule-chain": "Rule Chain", - "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", - "type-input": "Input", - "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", - "directive-is-not-loaded": "Defined configuration directive '{{directiveName}}' is not available.", - "ui-resources-load-error": "Failed to load configuration ui resources.", - "invalid-target-rulechain": "Unable to resolve target rule chain!", - "test-script-function": "Test script function", - "message": "Message", - "message-type": "Message type", - "message-type-required": "Message type is required", - "metadata": "Metadata", - "metadata-required": "Metadata entries can't be empty.", - "output": "Output", - "test": "Test", - "help": "Help" + "details": "Подробности", + "events": "События", + "search": "Поиск правил", + "open-node-library": "Открыть библиотеку правил", + "add": "Добавить правило", + "name": "Название", + "name-required": "Название обязательно.", + "type": "Тип", + "description": "Описание", + "delete": "Удалить правило", + "select-all-objects": "Выделить все правила и связи", + "deselect-all-objects": "Отменить выделение правил и связей", + "delete-selected-objects": "Удалить выделенные правила и связи", + "delete-selected": "Удалить выделенные", + "select-all": "Выделить всё", + "copy-selected": "Копировать выделенное", + "deselect-all": "Отменить выделение", + "rulenode-details": "Подробности о правиле", + "debug-mode": "Режим отладки", + "configuration": "Настройки", + "link": "Связь", + "link-details": "Подробности о связи правила", + "add-link": "Добавить связь", + "link-label": "Метка связи", + "link-label-required": "Метка связи обязателен.", + "custom-link-label": "Пользовательская метка связи", + "custom-link-label-required": "Пользовательская метка связи обязателен.", + "link-labels": "Метки связи", + "link-labels-required": "Метки связи обязательны.", + "no-link-labels-found": "Метки связи не найдены", + "no-link-label-matching": "Метка '{{label}}' не найдена.", + "create-new-link-label": "Создать новую!", + "type-filter": "Фильтр", + "type-filter-details": "Фильтр входящих сообщений с заданными условиями", + "type-enrichment": "Насыщение", + "type-enrichment-details": "Добавить данные в метадату сообщения", + "type-transformation": "Преобразование", + "type-transformation-details": "Изменить содержимое сообщение и его метадату", + "type-action": "Действие", + "type-action-details": "Выполнить заданное действие", + "type-external": "Сторонние", + "type-external-details": "Взаимодействовать со сторонними системами", + "type-rule-chain": "Цепочка правил", + "type-rule-chain-details": "Перенаправить входящее сообщение в другую цепочку правил", + "type-input": "Вход", + "type-input-details": "Логический вход цепочки правил перенаправляет входящие сообщения в следующее правило", + "type-unknown": "Неизвестный", + "type-unknown-details": "Неопределенное правило", + "directive-is-not-loaded": "Указанная директива конфигурации '{{directiveName}}' не доступна.", + "ui-resources-load-error": "Не удалось загрузить UI ресурсы.", + "invalid-target-rulechain": "Не удалось определить целевую цепочку правил!", + "test-script-function": "Протестировать скрипт", + "message": "Сообщение", + "message-type": "Тип сообщения", + "select-message-type": "Выбрать тип сообщения", + "message-type-required": "Тип сообщения обязателен", + "metadata": "Метаданные", + "metadata-required": "Метаданные объекта не могут быть пустыми.", + "output": "Выход", + "test": "Протестировать", + "help": "Помощь" }, "tenant": { + "tenant": "Владелец", "tenants": "Владельцы", "management": "Управление владельцами", "add": "Добавить владельца", @@ -1144,6 +1311,13 @@ "title": "Имя", "title-required": "Имя обязательно.", "description": "Описание" + "details": "Подробности", + "events": "События", + "copyId": "Копировать ИД владельца", + "idCopiedMessage": "ИД владельца скопирован в буфер обмена", + "select-tenant": "Выбрать владельца", + "no-tenants-matching": "Владельцы, соответствующие '{{entity}}', не найдены.", + "tenant-required": "Владелец обязателен" }, "timeinterval": { "seconds-interval": "{ seconds, plural, one {1 секунда} few {# секунды} other {# секунд} }", @@ -1171,6 +1345,7 @@ "time-period": "Период времени" }, "user": { + "user": "Пользователь", "users": "Пользователи", "customer-users": "Пользователи клиента", "tenant-admins": "Администраторы владельца", @@ -1192,11 +1367,25 @@ "resend-activation": "Повторить отправку активационного письма", "email": "Эл. адрес", "email-required": "Эл. адрес обязателен.", + "invalid-email-format": "Не правильный формат письма.", "first-name": "Имя", "last-name": "Фамилия", "description": "Описание", "default-dashboard": "Дашборд по умолчанию", - "always-fullscreen": "Всегда во весь экран" + "always-fullscreen": "Всегда в полноэкранном режиме", + "select-user": "Выбрать пользователя", + "no-users-matching": "Пользователи, соответствующие '{{entity}}', не найдены.", + "user-required": "Пользователь обязателен", + "activation-method": "Метод активации", + "display-activation-link": "Отобразить ссылку для активации", + "send-activation-mail": "Отправить активационное письмо", + "activation-link": "Активационная ссылка для пользователя", + "activation-link-text": "Для активации пользователя используйте ссылку :", + "copy-activation-link": "Копировать активационную ссылку", + "activation-link-copied-message": "Ссылка для активации пользователя скопировано в буфер обмена", + "details": "Подробности", + "login-as-tenant-admin": "Войти как администратор владельца", + "login-as-customer-user": "Войти как пользователь клиента" }, "value": { "type": "Тип значения", @@ -1210,7 +1399,8 @@ "boolean": "Логический тип", "boolean-value": "Логическое значение", "false": "Ложь", - "true": "Правда" + "true": "Правда", + "long": "Целое число" }, "widget": { "widget-library": "Галерея виджетов", @@ -1225,8 +1415,11 @@ "remove-widget-title": "Вы точно хотите удалить виджет '{{widgetTitle}}'?", "remove-widget-text": "Внимание, после подтверждения виджет и все связанные с ним данные будут безвозвратно утеряны.", "timeseries": "Выборка по времени", + "search-data": "Search data", + "no-data-found": "No data found", "latest-values": "Последние значения", "rpc": "Управляющий виджет", + "alarm": "Alarm widget", "static": "Статический виджет", "select-widget-type": "Выберите тип виджета", "missing-widget-title-error": "Укажите название виджета!", @@ -1262,16 +1455,16 @@ "export": "Экспортировать виджет" }, "widget-action": { - "header-button": "Widget header button", - "open-dashboard-state": "Navigate to new dashboard state", - "update-dashboard-state": "Update current dashboard state", - "open-dashboard": "Navigate to other dashboard", - "custom": "Custom action", - "target-dashboard-state": "Target dashboard state", - "target-dashboard-state-required": "Target dashboard state is required", - "set-entity-from-widget": "Set entity from widget", - "target-dashboard": "Target dashboard", - "open-right-layout": "Open right dashboard layout (mobile view)" + "header-button": "Кнопка заголовка виджета", + "open-dashboard-state": "Перейти к новомум состоянию дашборда", + "update-dashboard-state": "Обновить текущее состояние дашборда", + "open-dashboard": "Перейти к другому дашборду", + "custom": "Пользовательское действие", + "target-dashboard-state": "Целевое состояние дашборда", + "target-dashboard-state-required": "Целевое состояние дашборда обязательно", + "set-entity-from-widget": "Установить объект из виджета", + "target-dashboard": "Целевой дашборд", + "open-right-layout": "Открыть мобильный режим дашборда" }, "widgets-bundle": { "current": "Текущий набор", @@ -1312,6 +1505,8 @@ "background-color": "Цвет фона", "text-color": "Цвет текста", "padding": "Отступ", + "margin": "Margin", + "widget-style": "Стиль виджета", "title-style": "Стиль названия", "mobile-mode-settings": "Настройки мобильного режима", "order": "Порядок", @@ -1322,11 +1517,29 @@ "use-dashboard-timewindow": "Использовать временное окно дашборда", "display-legend": "Показать легенду", "datasources": "Источники данных", + "maximum-datasources": "Максимальной количество источников данных равно {{count}}", "datasource-type": "Тип", "datasource-parameters": "Параметры", "remove-datasource": "Удалить источник данных", "add-datasource": "Добавить источник данных", "target-device": "Целевое устройство" + "alarm-source": "Источник оповещения", + "actions": "Действия", + "action": "Действие", + "add-action": "Добавить действие", + "search-actions": "Поиск действий", + "action-source": "Источник действий", + "action-source-required": "Источник действий обязателен.", + "action-name": "Название", + "action-name-required": "Название действия обязательно.", + "action-name-not-unique": "Действие с таким именем уже существует.
Название должно быть уникально в рамках одного источника действий.", + "action-icon": "Иконка", + "action-type": "Тип", + "action-type-required": "Тип действий обязателен.", + "edit-action": "Редактировать действие", + "delete-action": "Удалить действие", + "delete-action-title": "Удалить действие виджета", + "delete-action-text": "Вы точно хотите удалить действие виджета '{{actionName}}'?" }, "widget-type": { "import": "Импортировать тип виджета", @@ -1337,32 +1550,31 @@ "invalid-widget-type-file-error": "Не удалось импортировать виджет: неизвестная схема данных типа виджета." }, "icon": { - "icon": "Icon", - "select-icon": "Select icon", - "material-icons": "Material icons", - "show-all": "Show all icons" + "icon": "Иконка", + "select-icon": "Выбрать иконку", + "material-icons": "Иконки в стиле Material", + "show-all": "Показать все иконки" }, "custom": { "widget-action": { - "action-cell-button": "Action cell button", - "row-click": "On row click", - "marker-click": "On marker click", - "tooltip-tag-action": "Tooltip tag action" + "action-cell-button": "Кнопка действия ячейки", + "row-click": "Действий при щелчке на строку", + "marker-click": "Действия при щелчке на указателе", + "tooltip-tag-action": "Действие при подсказке" } }, "language": { "language": "Язык", "locales": { "en_US": "Английский", - "fr_FR": "Французский", "zh_CN": "Китайский", "ko_KR": "Корейский", "es_ES": "Испанский", "it_IT": "Итальянский", "ru_RU": "Русский", - "ja_JA": "Японский", - "tr_TR": "Турецкий" + "tr_TR": "Турецкий", + "fr_FR": "Французский", + "ja_JA": "Японский" } - } } From 8e590a52945ff86857697bfa5a278d280bc483a7 Mon Sep 17 00:00:00 2001 From: dvk2018 Date: Tue, 25 Dec 2018 17:19:48 +0500 Subject: [PATCH 11/13] Add missing commas in JSON. --- ui/src/app/locale/locale.constant-ru_RU.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ui/src/app/locale/locale.constant-ru_RU.json b/ui/src/app/locale/locale.constant-ru_RU.json index 07ae86e5a0..3c6126ebfd 100644 --- a/ui/src/app/locale/locale.constant-ru_RU.json +++ b/ui/src/app/locale/locale.constant-ru_RU.json @@ -555,7 +555,7 @@ "alarm-fields-required": "Параметры оповещения обязательны.", "function-types": "Тип функции", "function-types-required": "Тип функции обязателен.", - "maximum-function-types": "Максимальное количество типов функции равно {{count}}" + "maximum-function-types": "Максимальное количество типов функции равно {{count}}", "time-description": "время текущего значения;", "value-description": "текущее значение;", "prev-value-description": "результат предыдущего вызова функции;", @@ -664,7 +664,7 @@ "unable-delete-device-alias-text": "Не удалось удалить псевдоним '{{deviceAlias}}' устройства, т.к. он используется следующими виджетами:
{{widgetsList}}", "is-gateway": "Гейтвей", "public": "Общедоступный", - "device-public": "Устройство общедоступно" + "device-public": "Устройство общедоступно", "select-device": "Выбрать устройство" }, "dialog": { @@ -1310,7 +1310,7 @@ "delete-tenants-text": "Внимание, после подтверждения выбранные Владельцы и все связанные с ними данные будут безвозвратно утеряны.", "title": "Имя", "title-required": "Имя обязательно.", - "description": "Описание" + "description": "Описание", "details": "Подробности", "events": "События", "copyId": "Копировать ИД владельца", @@ -1522,7 +1522,7 @@ "datasource-parameters": "Параметры", "remove-datasource": "Удалить источник данных", "add-datasource": "Добавить источник данных", - "target-device": "Целевое устройство" + "target-device": "Целевое устройство", "alarm-source": "Источник оповещения", "actions": "Действия", "action": "Действие", From 0686d3a21b38f459efe0094b965cfff2b95c4345 Mon Sep 17 00:00:00 2001 From: nordmif Date: Tue, 11 Dec 2018 20:11:12 +0200 Subject: [PATCH 12/13] fixed conflicts --- .../server/controller/TelemetryController.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java index bebd2cc4d3..4748c22e25 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TelemetryController.java @@ -279,8 +279,14 @@ public class TelemetryController extends BaseController { deleteFromTs = 0L; deleteToTs = System.currentTimeMillis(); } else { - deleteFromTs = startTs; - deleteToTs = endTs; + if (startTs == null || endTs == null) { + deleteToTs = endTs; + return getImmediateDeferredResult("When deleteAllDataForKeys is false, start and end timestamp values shouldn't be empty", HttpStatus.BAD_REQUEST); + } + else{ + deleteFromTs = startTs; + deleteToTs = endTs; + } } return accessValidator.validateEntityAndCallback(user, entityIdStr, (result, tenantId, entityId) -> { From 9590c37720ac9c7c175a90e6450053a941da7940 Mon Sep 17 00:00:00 2001 From: dvk2018 Date: Sat, 8 Dec 2018 17:35:13 +0500 Subject: [PATCH 13/13] Add 'Reconnect' and 'RTU over TCP' options to TCP Modbus extension configuration. --- .../extension-form-modbus.directive.js | 45 ++++++-- .../extension-form-modbus.tpl.html | 104 +++++++++++------- ui/src/app/locale/locale.constant-en_US.json | 2 + 3 files changed, 99 insertions(+), 52 deletions(-) diff --git a/ui/src/app/extension/extensions-forms/extension-form-modbus.directive.js b/ui/src/app/extension/extensions-forms/extension-form-modbus.directive.js index 2dfc961d02..96c398b897 100644 --- a/ui/src/app/extension/extensions-forms/extension-form-modbus.directive.js +++ b/ui/src/app/extension/extensions-forms/extension-form-modbus.directive.js @@ -31,17 +31,38 @@ export default function ExtensionFormModbusDirective($compile, $templateCache, $ var linker = function(scope, element) { + function TcpTransport() { + this.type = "tcp", + this.host = "localhost", + this.port = 502, + this.timeout = 5000, + this.reconnect = true, + this.rtuOverTcp = false + } + + function UdpTransport() { + this.type = "udp", + this.host = "localhost", + this.port = 502, + this.timeout = 5000 + } + + function RtuTransport() { + this.type = "rtu", + this.portName = "COM1", + this.encoding = "ascii", + this.timeout = 5000, + this.baudRate = 115200, + this.dataBits = 7, + this.stopBits = 1, + this.parity ="even" + } function Server() { - this.transport = { - "type": "tcp", - "host": "localhost", - "port": 502, - "timeout": 3000 - }; + this.transport = new TcpTransport(); this.devices = [] } - + function Device() { this.unitId = 1; this.deviceName = ""; @@ -105,9 +126,13 @@ export default function ExtensionFormModbusDirective($compile, $templateCache, $ scope.onTransportChanged = function(server) { var type = server.transport.type; - server.transport = {}; - server.transport.type = type; - server.transport.timeout = 3000; + if (type === "tcp") { + server.transport = new TcpTransport(); + } else if (type === "udp") { + server.transport = new UdpTransport(); + } else if (type === "rtu") { + server.transport = new RtuTransport(); + } scope.theForm.$setDirty(); }; diff --git a/ui/src/app/extension/extensions-forms/extension-form-modbus.tpl.html b/ui/src/app/extension/extensions-forms/extension-form-modbus.tpl.html index 989d3f07db..508ddc0c42 100644 --- a/ui/src/app/extension/extensions-forms/extension-form-modbus.tpl.html +++ b/ui/src/app/extension/extensions-forms/extension-form-modbus.tpl.html @@ -73,49 +73,69 @@ -
- - - -
-
extension.field-required
-
-
+
+
+ + + +
+
extension.field-required
+
+
- - - -
-
extension.field-required
-
extension.port-range
-
extension.port-range
-
-
- - - - -
-
extension.field-required
-
-
+ + + +
+
extension.field-required
+
extension.port-range
+
extension.port-range
+
+
+ + + + +
+
extension.field-required
+
+
+
+ +
+ + {{ 'extension.modbus-tcp-reconnect' | translate }} + + + + + {{ 'extension.modbus-rtu-over-tcp' | translate }} + + +
diff --git a/ui/src/app/locale/locale.constant-en_US.json b/ui/src/app/locale/locale.constant-en_US.json index 30e1eb119b..3aa520a955 100644 --- a/ui/src/app/locale/locale.constant-en_US.json +++ b/ui/src/app/locale/locale.constant-en_US.json @@ -1008,6 +1008,8 @@ "modbus-add-server": "Add server/slave", "modbus-add-server-prompt": "Please add server/slave", "modbus-transport": "Transport", + "modbus-tcp-reconnect": "Automatically reconnect", + "modbus-rtu-over-tcp": "RTU over TCP", "modbus-port-name": "Serial port name", "modbus-encoding": "Encoding", "modbus-parity": "Parity",