diff --git a/application/pom.xml b/application/pom.xml index ddd91e07e9..91965dfed5 100644 --- a/application/pom.xml +++ b/application/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard application diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 8433fdb1ea..2cc7e470c2 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -67,6 +67,7 @@ import org.thingsboard.server.service.encoding.DataDecodingEncodingService; import org.thingsboard.server.service.executors.ClusterRpcCallbackExecutorService; import org.thingsboard.server.service.executors.DbCallbackExecutorService; import org.thingsboard.server.service.executors.ExternalCallExecutorService; +import org.thingsboard.server.service.executors.SharedEventLoopGroupService; import org.thingsboard.server.service.mail.MailExecutorService; import org.thingsboard.server.service.rpc.DeviceRpcService; import org.thingsboard.server.service.script.JsExecutorService; @@ -206,6 +207,10 @@ public class ActorSystemContext { @Getter private ExternalCallExecutorService externalCallExecutorService; + @Autowired + @Getter + private SharedEventLoopGroupService sharedEventLoopGroupService; + @Autowired @Getter private MailService mailService; diff --git a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java index ed50bdafa6..90a9d56e0c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ruleChain/DefaultTbContext.java @@ -17,6 +17,7 @@ package org.thingsboard.server.actors.ruleChain; import akka.actor.ActorRef; import com.datastax.driver.core.utils.UUIDs; +import io.netty.channel.EventLoopGroup; import org.springframework.util.StringUtils; import org.thingsboard.rule.engine.api.ListeningExecutor; import org.thingsboard.rule.engine.api.MailService; @@ -238,6 +239,11 @@ class DefaultTbContext implements TbContext { return mainCtx.getRuleChainTransactionService(); } + @Override + public EventLoopGroup getSharedEventLoop() { + return mainCtx.getSharedEventLoopGroupService().getSharedEventLoopGroup(); + } + @Override public MailService getMailService() { if (mainCtx.isAllowSystemMailService()) { diff --git a/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java b/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java index fabd345b64..221915d02c 100644 --- a/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java +++ b/application/src/main/java/org/thingsboard/server/service/executors/AbstractListeningExecutor.java @@ -34,7 +34,7 @@ public abstract class AbstractListeningExecutor implements ListeningExecutor { @PostConstruct public void init() { - this.service = MoreExecutors.listeningDecorator(Executors.newFixedThreadPool(getThreadPollSize())); + this.service = MoreExecutors.listeningDecorator(Executors.newWorkStealingPool(getThreadPollSize())); } @PreDestroy diff --git a/application/src/main/java/org/thingsboard/server/service/executors/SharedEventLoopGroupService.java b/application/src/main/java/org/thingsboard/server/service/executors/SharedEventLoopGroupService.java new file mode 100644 index 0000000000..e61b0db0f6 --- /dev/null +++ b/application/src/main/java/org/thingsboard/server/service/executors/SharedEventLoopGroupService.java @@ -0,0 +1,48 @@ +/** + * Copyright © 2016-2019 The Thingsboard Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.thingsboard.server.service.executors; + +import com.google.common.util.concurrent.MoreExecutors; +import io.netty.channel.EventLoopGroup; +import io.netty.channel.nio.NioEventLoopGroup; +import lombok.Getter; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +@Component +public class SharedEventLoopGroupService { + + @Getter + private EventLoopGroup sharedEventLoopGroup; + + @PostConstruct + public void init() { + this.sharedEventLoopGroup = new NioEventLoopGroup(); + } + + @PreDestroy + public void destroy() { + if (this.sharedEventLoopGroup != null) { + this.sharedEventLoopGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS); + } + } + +} diff --git a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java index f365ef68dc..62e7c24b1a 100644 --- a/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java +++ b/application/src/main/java/org/thingsboard/server/service/script/AbstractNashornJsInvokeService.java @@ -42,7 +42,7 @@ public abstract class AbstractNashornJsInvokeService extends AbstractJsInvokeSer public void init() { if (useJsSandbox()) { sandbox = NashornSandboxes.create(); - monitorExecutorService = Executors.newFixedThreadPool(getMonitorThreadPoolSize()); + monitorExecutorService = Executors.newWorkStealingPool(getMonitorThreadPoolSize()); sandbox.setExecutor(monitorExecutorService); sandbox.setMaxCPUTime(getMaxCpuTime()); sandbox.allowNoBraces(false); diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index ba9382aa2d..235646f6c2 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -200,13 +200,13 @@ actors: # Specify thread pool size for database request callbacks executor service db_callback_thread_pool_size: "${ACTORS_RULE_DB_CALLBACK_THREAD_POOL_SIZE:1}" # Specify thread pool size for javascript executor service - js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:10}" + js_thread_pool_size: "${ACTORS_RULE_JS_THREAD_POOL_SIZE:50}" # Specify thread pool size for mail sender executor service - mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:10}" + mail_thread_pool_size: "${ACTORS_RULE_MAIL_THREAD_POOL_SIZE:50}" # Whether to allow usage of system mail service for rules allow_system_mail_service: "${ACTORS_RULE_ALLOW_SYSTEM_MAIL_SERVICE:true}" # Specify thread pool size for external call service - external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:10}" + external_call_thread_pool_size: "${ACTORS_RULE_EXTERNAL_CALL_THREAD_POOL_SIZE:50}" chain: # Errors for particular actor are persisted once per specified amount of milliseconds error_persist_frequency: "${ACTORS_RULE_CHAIN_ERROR_FREQUENCY:3000}" diff --git a/common/data/pom.xml b/common/data/pom.xml index a289ee7d04..bb5d9c76ff 100644 --- a/common/data/pom.xml +++ b/common/data/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT common org.thingsboard.common diff --git a/common/message/pom.xml b/common/message/pom.xml index 24e2d8bb38..62fffe5d19 100644 --- a/common/message/pom.xml +++ b/common/message/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT common org.thingsboard.common diff --git a/common/pom.xml b/common/pom.xml index bb689002e1..3e7aa22dfc 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard common diff --git a/common/queue/pom.xml b/common/queue/pom.xml index aa5542cede..694d64ac21 100644 --- a/common/queue/pom.xml +++ b/common/queue/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/coap/pom.xml b/common/transport/coap/pom.xml index b27fcd7763..18d2cc7590 100644 --- a/common/transport/coap/pom.xml +++ b/common/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/http/pom.xml b/common/transport/http/pom.xml index e867aa1605..0933bb0b40 100644 --- a/common/transport/http/pom.xml +++ b/common/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/mqtt/pom.xml b/common/transport/mqtt/pom.xml index 95832aac51..08a8d56ef0 100644 --- a/common/transport/mqtt/pom.xml +++ b/common/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/common/transport/pom.xml b/common/transport/pom.xml index b63d6488bd..f2b70be45c 100644 --- a/common/transport/pom.xml +++ b/common/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT common org.thingsboard.common diff --git a/common/transport/transport-api/pom.xml b/common/transport/transport-api/pom.xml index 407c414fce..aae1c3f930 100644 --- a/common/transport/transport-api/pom.xml +++ b/common/transport/transport-api/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.common - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.common.transport diff --git a/dao/pom.xml b/dao/pom.xml index 817a5449f6..3b73edede3 100644 --- a/dao/pom.xml +++ b/dao/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard dao diff --git a/docker/tb-js-executor.env b/docker/tb-js-executor.env index f7f24acabf..38f283cd1a 100644 --- a/docker/tb-js-executor.env +++ b/docker/tb-js-executor.env @@ -4,4 +4,5 @@ TB_KAFKA_SERVERS=kafka:9092 LOGGER_LEVEL=info LOG_FOLDER=logs LOGGER_FILENAME=tb-js-executor-%DATE%.log -DOCKER_MODE=true \ No newline at end of file +DOCKER_MODE=true +SCRIPT_BODY_TRACE_FREQUENCY=1000 \ No newline at end of file diff --git a/msa/black-box-tests/pom.xml b/msa/black-box-tests/pom.xml index 813d344605..40461e1e9f 100644 --- a/msa/black-box-tests/pom.xml +++ b/msa/black-box-tests/pom.xml @@ -21,7 +21,7 @@ org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/js-executor/api/jsInvokeMessageProcessor.js b/msa/js-executor/api/jsInvokeMessageProcessor.js index f79233ef76..1a1df75e09 100644 --- a/msa/js-executor/api/jsInvokeMessageProcessor.js +++ b/msa/js-executor/api/jsInvokeMessageProcessor.js @@ -15,16 +15,20 @@ */ 'use strict'; -const logger = require('../config/logger')('JsInvokeMessageProcessor'), +const config = require('config'), + logger = require('../config/logger')('JsInvokeMessageProcessor'), Utils = require('./utils'), js = require('./jsinvoke.proto').js, KeyedMessage = require('kafka-node').KeyedMessage, JsExecutor = require('./jsExecutor'); +const scriptBodyTraceFrequency = Number(config.get('script.script_body_trace_frequency')); + function JsInvokeMessageProcessor(producer) { this.producer = producer; this.executor = new JsExecutor(); this.scriptMap = {}; + this.executedScriptsCounter = 0; } JsInvokeMessageProcessor.prototype.onJsInvokeMessage = function(message) { @@ -74,6 +78,13 @@ JsInvokeMessageProcessor.prototype.processCompileRequest = function(requestId, r JsInvokeMessageProcessor.prototype.processInvokeRequest = function(requestId, responseTopic, invokeRequest) { var scriptId = getScriptId(invokeRequest); logger.debug('[%s] Processing invoke request, scriptId: [%s]', requestId, scriptId); + this.executedScriptsCounter++; + if ( this.executedScriptsCounter >= scriptBodyTraceFrequency ) { + this.executedScriptsCounter = 0; + if (logger.levels[logger.level] >= logger.levels['debug']) { + logger.debug('[%s] Executing script body: [%s]', scriptId, invokeRequest.scriptBody); + } + } this.getOrCompileScript(scriptId, invokeRequest.scriptBody).then( (script) => { this.executor.executeScript(script, invokeRequest.args, invokeRequest.timeout).then( diff --git a/msa/js-executor/config/custom-environment-variables.yml b/msa/js-executor/config/custom-environment-variables.yml index d074bd9e45..99f47cb5f1 100644 --- a/msa/js-executor/config/custom-environment-variables.yml +++ b/msa/js-executor/config/custom-environment-variables.yml @@ -23,3 +23,6 @@ logger: level: "LOGGER_LEVEL" path: "LOG_FOLDER" filename: "LOGGER_FILENAME" + +script: + script_body_trace_frequency: "SCRIPT_BODY_TRACE_FREQUENCY" diff --git a/msa/js-executor/config/default.yml b/msa/js-executor/config/default.yml index 9f82caa016..fb470567e7 100644 --- a/msa/js-executor/config/default.yml +++ b/msa/js-executor/config/default.yml @@ -24,3 +24,6 @@ logger: level: "info" path: "logs" filename: "tb-js-executor-%DATE%.log" + +script: + script_body_trace_frequency: "1000" diff --git a/msa/js-executor/package.json b/msa/js-executor/package.json index 7ec6f92e7e..b1c512e54c 100644 --- a/msa/js-executor/package.json +++ b/msa/js-executor/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-js-executor", "private": true, - "version": "2.3.0", + "version": "2.3.1", "description": "ThingsBoard JavaScript Executor Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/js-executor/pom.xml b/msa/js-executor/pom.xml index 97c4b166b5..e5102798a7 100644 --- a/msa/js-executor/pom.xml +++ b/msa/js-executor/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/pom.xml b/msa/pom.xml index 180ecae29a..5965b7f2fc 100644 --- a/msa/pom.xml +++ b/msa/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard msa diff --git a/msa/tb-node/pom.xml b/msa/tb-node/pom.xml index bc0bd0ee60..d23a9b0710 100644 --- a/msa/tb-node/pom.xml +++ b/msa/tb-node/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/tb/pom.xml b/msa/tb/pom.xml index f1eb88fffc..8a815e2e00 100644 --- a/msa/tb/pom.xml +++ b/msa/tb/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/transport/coap/pom.xml b/msa/transport/coap/pom.xml index df185220a2..f92330a2d9 100644 --- a/msa/transport/coap/pom.xml +++ b/msa/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/http/pom.xml b/msa/transport/http/pom.xml index 628f0665eb..a45e05356a 100644 --- a/msa/transport/http/pom.xml +++ b/msa/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/mqtt/pom.xml b/msa/transport/mqtt/pom.xml index 33eeaf9146..5347497606 100644 --- a/msa/transport/mqtt/pom.xml +++ b/msa/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard.msa - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.msa.transport diff --git a/msa/transport/pom.xml b/msa/transport/pom.xml index 644605eafe..a78532f0c6 100644 --- a/msa/transport/pom.xml +++ b/msa/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/msa/web-ui/package.json b/msa/web-ui/package.json index 43a7962aee..0bdb6cfa84 100644 --- a/msa/web-ui/package.json +++ b/msa/web-ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard-web-ui", "private": true, - "version": "2.3.0", + "version": "2.3.1", "description": "ThingsBoard Web UI Microservice", "main": "server.js", "bin": "server.js", diff --git a/msa/web-ui/pom.xml b/msa/web-ui/pom.xml index 3768993e9b..8fb039b27e 100644 --- a/msa/web-ui/pom.xml +++ b/msa/web-ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT msa org.thingsboard.msa diff --git a/netty-mqtt/pom.xml b/netty-mqtt/pom.xml index 4e69394015..1af619fec2 100644 --- a/netty-mqtt/pom.xml +++ b/netty-mqtt/pom.xml @@ -19,12 +19,12 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard org.thingsboard netty-mqtt - 2.3.0 + 2.3.1-SNAPSHOT jar Netty MQTT Client diff --git a/pom.xml b/pom.xml index 794aa2ff9b..f2cde239b7 100755 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard thingsboard - 2.3.0 + 2.3.1-SNAPSHOT pom Thingsboard diff --git a/rule-engine/pom.xml b/rule-engine/pom.xml index a704dd7d4e..53a516d7cb 100644 --- a/rule-engine/pom.xml +++ b/rule-engine/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard rule-engine diff --git a/rule-engine/rule-engine-api/pom.xml b/rule-engine/rule-engine-api/pom.xml index 15f629a5d8..aed0372b0b 100644 --- a/rule-engine/rule-engine-api/pom.xml +++ b/rule-engine/rule-engine-api/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java index d3476a470c..9ebc610e1b 100644 --- a/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java +++ b/rule-engine/rule-engine-api/src/main/java/org/thingsboard/rule/engine/api/TbContext.java @@ -15,6 +15,7 @@ */ package org.thingsboard.rule.engine.api; +import io.netty.channel.EventLoopGroup; import org.thingsboard.server.common.data.id.EntityId; import org.thingsboard.server.common.data.id.RuleNodeId; import org.thingsboard.server.common.data.id.TenantId; @@ -105,4 +106,7 @@ public interface TbContext { String getNodeId(); RuleChainTransactionService getRuleChainTransactionService(); + + EventLoopGroup getSharedEventLoop(); + } diff --git a/rule-engine/rule-engine-components/pom.xml b/rule-engine/rule-engine-components/pom.xml index d95003c9df..01253f0acc 100644 --- a/rule-engine/rule-engine-components/pom.xml +++ b/rule-engine/rule-engine-components/pom.xml @@ -22,7 +22,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT rule-engine org.thingsboard.rule-engine diff --git a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java index 3ffa910802..dd17414b87 100644 --- a/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java +++ b/rule-engine/rule-engine-components/src/main/java/org/thingsboard/rule/engine/mqtt/TbMqttNode.java @@ -59,15 +59,13 @@ public class TbMqttNode implements TbNode { private TbMqttNodeConfiguration config; - private EventLoopGroup eventLoopGroup; private MqttClient mqttClient; @Override public void init(TbContext ctx, TbNodeConfiguration configuration) throws TbNodeException { try { this.config = TbNodeUtils.convert(configuration, TbMqttNodeConfiguration.class); - this.eventLoopGroup = new NioEventLoopGroup(); - this.mqttClient = initClient(); + this.mqttClient = initClient(ctx); } catch (Exception e) { throw new TbNodeException(e); } @@ -99,12 +97,9 @@ public class TbMqttNode implements TbNode { if (this.mqttClient != null) { this.mqttClient.disconnect(); } - if (this.eventLoopGroup != null) { - this.eventLoopGroup.shutdownGracefully(0, 5, TimeUnit.SECONDS); - } } - private MqttClient initClient() throws Exception { + private MqttClient initClient(TbContext ctx) throws Exception { Optional sslContextOpt = initSslContext(); MqttClientConfig config = sslContextOpt.isPresent() ? new MqttClientConfig(sslContextOpt.get()) : new MqttClientConfig(); if (!StringUtils.isEmpty(this.config.getClientId())) { @@ -113,7 +108,7 @@ public class TbMqttNode implements TbNode { config.setCleanSession(this.config.isCleanSession()); this.config.getCredentials().configure(config); MqttClient client = MqttClient.create(config, null); - client.setEventLoop(this.eventLoopGroup); + client.setEventLoop(ctx.getSharedEventLoop()); Future connectFuture = client.connect(this.config.getHost(), this.config.getPort()); MqttConnectResult result; try { diff --git a/tools/pom.xml b/tools/pom.xml index 6da6c2fdc1..7f3e79be8c 100644 --- a/tools/pom.xml +++ b/tools/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard tools diff --git a/transport/coap/pom.xml b/transport/coap/pom.xml index 05088b5bc6..874979c74d 100644 --- a/transport/coap/pom.xml +++ b/transport/coap/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/http/pom.xml b/transport/http/pom.xml index d3e5cc47b4..8fc24706d6 100644 --- a/transport/http/pom.xml +++ b/transport/http/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/mqtt/pom.xml b/transport/mqtt/pom.xml index cc0628e399..10dc810ff8 100644 --- a/transport/mqtt/pom.xml +++ b/transport/mqtt/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT transport org.thingsboard.transport diff --git a/transport/pom.xml b/transport/pom.xml index 4a70402d66..05abf6aa7b 100644 --- a/transport/pom.xml +++ b/transport/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard transport diff --git a/ui/package-lock.json b/ui/package-lock.json index 30fd603198..9b8224e0ff 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -1,6 +1,6 @@ { "name": "thingsboard", - "version": "2.3.0", + "version": "2.3.1", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/ui/package.json b/ui/package.json index 7345ae6425..2600c62438 100644 --- a/ui/package.json +++ b/ui/package.json @@ -1,7 +1,7 @@ { "name": "thingsboard", "private": true, - "version": "2.3.0", + "version": "2.3.1", "description": "ThingsBoard UI", "licenses": [ { diff --git a/ui/pom.xml b/ui/pom.xml index d5f91db026..591e92c458 100644 --- a/ui/pom.xml +++ b/ui/pom.xml @@ -20,7 +20,7 @@ 4.0.0 org.thingsboard - 2.3.0 + 2.3.1-SNAPSHOT thingsboard org.thingsboard diff --git a/ui/src/app/locale/locale.constant-it_IT.json b/ui/src/app/locale/locale.constant-it_IT.json index abaabb6d43..986fdc19a0 100644 --- a/ui/src/app/locale/locale.constant-it_IT.json +++ b/ui/src/app/locale/locale.constant-it_IT.json @@ -133,8 +133,13 @@ "min-polling-interval-message": "L'intervallo di polling deve essere di almeno 1 sec.", "aknowledge-alarms-title": "Conferma { count, plural, 1 {1 allarme} other {# allarmi} }", "aknowledge-alarms-text": "Sei sicuro di voler confermare { count, plural, 1 {1 allarme} other {# allarmi} }?", + "aknowledge-alarm-title": "Conferma allarme", + "aknowledge-alarm-text": "Sei sicuro di voler confermare l'allarme?", "clear-alarms-title": "Elimina { count, plural, 1 {1 allarme} other {# allarmi} }", - "clear-alarms-text": "Sei sicuro di voler eliminare { count, plural, 1 {1 allarme} other {# allarmi} }?" + "clear-alarms-text": "Sei sicuro di voler eliminare { count, plural, 1 {1 allarme} other {# allarmi} }?", + "clear-alarm-title": "Elimina allarme", + "clear-alarm-text": "Sei sicuro di voler eliminare l'allarme?", + "alarm-status-filter": "Filtro stato allarme" }, "alias": { "add": "Aggiungi alias", @@ -145,7 +150,7 @@ "filter-type-single-entity": "Singola entità", "filter-type-entity-list": "Lista Entità", "filter-type-entity-name": "Nome Entità", - "filter-type-state-entity": "Entity from dashboard state", + "filter-type-state-entity": "Entità dallo stato della dashboard", "filter-type-state-entity-description": "Entità prelevata dai parametri di stato della dashboard", "filter-type-asset-type": "Tipo di Asset", "filter-type-asset-type-description": "Asset di tipo '{{assetType}}'", @@ -153,26 +158,31 @@ "filter-type-device-type": "Tipo di dispositivo", "filter-type-device-type-description": "Dispositivi di tipo '{{deviceType}}'", "filter-type-device-type-and-name-description": "Dispositivi di tipo '{{deviceType}}' e con un nome che inizia per '{{prefix}}'", - "filter-type-relations-query": "Relations query", - "filter-type-relations-query-description": "{{entities}} that have {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-entity-view-type": "Tipo vista entità", + "filter-type-entity-view-type-description": "Viste entità di tipo '{{entityView}}'", + "filter-type-entity-view-type-and-name-description": "Viste entità di tipo '{{entityView}}' e con un nome che inizia per '{{prefix}}'", + "filter-type-relations-query": "Query relazioni", + "filter-type-relations-query-description": "{{entities}} che hanno una relazione {{relationType}} {{direction}} {{rootEntity}}", "filter-type-asset-search-query": "Query ricerca asset", - "filter-type-asset-search-query-description": "Assets with types {{assetTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-asset-search-query-description": "Asset di tipo {{assetTypes}} che hanno una relazione {{relationType}} {{direction}} {{rootEntity}}", "filter-type-device-search-query": "Query ricerca dispositivo", - "filter-type-device-search-query-description": "Devices with types {{deviceTypes}} that have {{relationType}} relation {{direction}} {{rootEntity}}", + "filter-type-device-search-query-description": "Dispositivi di tipo {{deviceTypes}} che hanno una relazione {{relationType}} {{direction}} {{rootEntity}}", + "filter-type-entity-view-search-query": "Query ricerca Vista entità", + "filter-type-entity-view-search-query-description": "Viste entità di tipo {{entityViewTypes}} che hanno una relazione {{relationType}} {{direction}} {{rootEntity}}", "entity-filter": "Filtro entità", - "resolve-multiple": "Resolve as multiple entities", + "resolve-multiple": "Risolvi come entità multiple", "filter-type": "Tipo di filtro", "filter-type-required": "Tipo di filtro richiesto.", "entity-filter-no-entity-matched": "Nessuna entità corrispondente al filtro specificato è stata trovata.", "no-entity-filter-specified": "Nessun filtro di entità specificato", - "root-state-entity": "Use dashboard state entity as root", + "root-state-entity": "Usa l'entità di stato della dashboard come radice", "root-entity": "Entità radice", - "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", + "state-entity-parameter-name": "Nome parametro entità di stato", + "default-state-entity": "Entità di stato predefinita", + "default-entity-parameter-name": "Predefinito", + "max-relation-level": "Massimo livello relazione", + "unlimited-level": "Illimitato", + "state-entity": "Entità di stato della dashboard", "all-entities": "Tutte le entità", "any-relation": "qualsiasi" }, @@ -212,10 +222,10 @@ "add-asset-text": "Aggiungi un nuovo asset", "asset-details": "Dettagli Asset", "assign-assets": "Assegna asset", - "assign-assets-text": "Assegna { count, plural, 1 {1 asset} other {# assets} } al cliente", + "assign-assets-text": "Assegna { count, plural, 1 {1 asset} other {# asset} } al cliente", "delete-assets": "Cancella asset", "unassign-assets": "Annulla assegnazione asset", - "unassign-assets-action-title": "Unassign { count, plural, 1 {1 asset} other {# assets} } from customer", + "unassign-assets-action-title": "Annulla assegnazione { count, plural, 1 {1 asset} other {# asset} } al cliente", "assign-new-asset": "Assegna un nuovo asset", "delete-asset-title": "Sei sicuro di voler cancellare l'asset '{{assetName}}'?", "delete-asset-text": "Attenzione, dopo la conferma l'asset e tutti i relativi dati non saranno più recuperabili.", @@ -234,7 +244,7 @@ "copyId": "Copia Id asset", "idCopiedMessage": "Id Asset copiato negli Appunti", "select-asset": "Seleziona asset", - "no-assets-matching": "Nessun asset corrispondente a '{{entity}}' é stato trovato.", + "no-assets-matching": "Nessun asset corrispondente a '{{entity}}' è stato trovato.", "asset-required": "Asset obbligatorio", "name-starts-with": "Asset con nome che inizia per" }, @@ -288,12 +298,17 @@ "type-suspended": "Sospeso", "type-credentials-read": "Credenziali lette", "type-attributes-read": "Attributi letti", - "status-success": "Success", - "status-failure": "Failure", + "type-relation-add-or-update": "Relazione aggiornata", + "type-relation-delete": "Relazione eliminata", + "type-relations-delete": "Eliminate tutte le relazioni", + "type-alarm-ack": "Confermato", + "type-alarm-clear": "Eliminato", + "status-success": "Successo", + "status-failure": "Fallito", "audit-log-details": "Dettaglio log audit", "no-audit-logs-prompt": "Log non trovati", "action-data": "Action data", - "failure-details": "Failure details", + "failure-details": "Dettagli fallimento", "search": "Cerca log audit", "clear-search": "Cancella ricerca" }, @@ -333,10 +348,12 @@ "dashboard": "Dashboard cliente", "dashboards": "Dashboard cliente", "devices": "Dispositivi cliente", + "entity-views": "Viste entità cliente", "assets": "Asset cliente", "public-dashboards": "Dashboard pubbliche", "public-devices": "Dispositivi pubblici", "public-assets": "Asset pubblici", + "public-entity-views": "Viste entità pubbliche", "add": "Aggiungi cliente", "delete": "Elimina cliente", "manage-customer-users": "Gestisci utenti cliente", @@ -388,14 +405,14 @@ "assign-dashboard-to-customer-text": "Seleziona le dashboard da assegnare al client", "assign-to-customer-text": "Seleziona il cliente a cui assegnare la/le dashboard", "assign-to-customer": "Assegna al cliente", - "unassign-from-customer": "Unassign from customer", + "unassign-from-customer": "Annulla assegnazione al cliente", "make-public": "Rendi pubblica la dashboard", "make-private": "Rendi privata la dashboard", "manage-assigned-customers": "Gestisci clienti assegnati", "assigned-customers": "Clienti assegnati", "assign-to-customers": "Assegna Dashboard ai Clienti", "assign-to-customers-text": "Seleziona i clienti da assegnare alla/alle dashboard", - "unassign-from-customers": "Unassign Dashboard(s) From Customers", + "unassign-from-customers": "Annulla assegnazione Dashboard ai Clienti", "unassign-from-customers-text": "Seleziona i clienti di cui annullare l'assegnazione alla/alle dashboard", "no-dashboards-text": "Nessuna dashboard trovata", "no-widgets": "Nessun widget configurato", @@ -412,10 +429,10 @@ "assign-dashboards": "Assegna dashboard", "assign-new-dashboard": "Assegna nuova dashboard", "assign-dashboards-text": "Assegna { count, plural, 1 {1 dashboard} other {# dashboard} } ai clienti", - "unassign-dashboards-action-text": "Annulla assegnazione { count, plural, 1 {1 dashboard} other {# dashboards} } ai clienti", + "unassign-dashboards-action-text": "Annulla assegnazione { count, plural, 1 {1 dashboard} other {# dashboard} } ai clienti", "delete-dashboards": "Elimina dashboard", "unassign-dashboards": "Annulla assegnazione dashboard", - "unassign-dashboards-action-title": "Annulla assegnazione { count, plural, 1 {1 dashboard} other {# dashboards} } al cliente", + "unassign-dashboards-action-title": "Annulla assegnazione { count, plural, 1 {1 dashboard} other {# dashboard} } al cliente", "delete-dashboard-title": "Sei sicuro di voler cancellare la dashboard '{{dashboardTitle}}'?", "delete-dashboard-text": "Attenzione, dopo la conferma la dashboard e tutti i suoi dati non saranno più recuperabili.", "delete-dashboards-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 dashboard} other {# dashboard} }?", @@ -425,7 +442,7 @@ "unassign-dashboard-text": "Dopo la conferma sarà annullata l'assegnazione della dashboard e questa non sarà più accessibile dal cliente.", "unassign-dashboard": "Annulla assegnazione dashboard", "unassign-dashboards-title": "Sei sicuro di voler annullare l'assegnazione di { count, plural, 1 {1 dashboard} other {# dashboard} }?", - "unassign-dashboards-text": "Dopo la conferma sarà annullata l'assegnazione di tutte le dashboards selezionate e queste non saranno più accessibili dal cliente.", + "unassign-dashboards-text": "Dopo la conferma sarà annullata l'assegnazione di tutte le dashboard selezionate e queste non saranno più accessibili dal cliente.", "public-dashboard-title": "La Dashboard è ora pubblica", "public-dashboard-text": "La dashboard {{dashboardTitle}} è ora pubblica e accessibile al link:", "public-dashboard-notice": "Nota: Ricorda di rendere pubblici i relativi dispositivi per accedere ai loro dati.", @@ -461,12 +478,12 @@ "vertical-margin-required": "Margine verticale obbligatorio.", "min-vertical-margin-message": "Ammesso un margine verticale minimo pari a 0.", "max-vertical-margin-message": "Ammesso un margine verticale massimo pari a 50.", - "autofill-height": "Auto fill layout height", + "autofill-height": "Riempi automaticamente altezza layout", "mobile-layout": "Impostazioni layout mobile", - "mobile-row-height": "Mobile row height, px", - "mobile-row-height-required": "Mobile row height value is required.", - "min-mobile-row-height-message": "Only 5 pixels is allowed as minimum mobile row height value.", - "max-mobile-row-height-message": "Only 200 pixels is allowed as maximum mobile row height value.", + "mobile-row-height": "Altezza riga mobile (px)", + "mobile-row-height-required": "Altezza riga mobile è richiesta.", + "min-mobile-row-height-message": "5 pixel è il minimo concesso al valore altezza riga mobile.", + "max-mobile-row-height-message": "200 pixel è il massimo concesso al valore altezza riga mobile.", "display-title": "Mostra titolo dashboard", "toolbar-always-open": "Mantieni aperta la barra degli strumenti", "title-color": "Colore titolo", @@ -527,18 +544,23 @@ "units": "Simbolo speciale da mostrare accanto al valore", "decimals": "Numero cifre decimali", "data-generation-func": "Funzione generazione dati", - "use-data-post-processing-func": "Use data post-processing function", + "use-data-post-processing-func": "Usa funzione dopo il processamento dei dati", "configuration": "Configurazione data key", "timeseries": "Serie temporali", "attributes": "Attributi", "alarm": "Campi allarme", - "timeseries-required": "Entity timeseries are required.", - "timeseries-or-attributes-required": "Entity timeseries/attributes are required.", + "timeseries-required": "Le serie temporali dell'entità sono richieste.", + "timeseries-or-attributes-required": "Le serie temporali o gli attributi dell'entità sono richiesti.", "maximum-timeseries-or-attributes": "Massimo { count, plural, 1 {1 serie temporale/attributo consentito.} other {# serie temporali/attributi consentiti.} }", "alarm-fields-required": "Campi allarme obbligatori.", "function-types": "Tipi funzione", "function-types-required": "Tipi funzione obbligatorio.", - "maximum-function-types": "Massimo { count, plural, 1 {1 tipo di funzione consentito.} other {# tipi di funzione consentiti} }" + "maximum-function-types": "Massimo { count, plural, 1 {1 tipo di funzione consentito.} other {# tipi di funzione consentiti} }", + "time-description": "timestamp del valore corrente;", + "value-description": "il valore corrente;", + "prev-value-description": "risultato della precedente chiamata alla funzione;", + "time-prev-description": "timestamp del valore precedente;", + "prev-orig-value-description": "valore precedente originale;" }, "datasource": { "type": "Tipo sorgente dati", @@ -563,11 +585,11 @@ "no-keys-found": "Nessuna chiave trovata.", "create-new-alias": "Creane uno nuovo!", "create-new-key": "Creane una nuova!", - "duplicate-alias-error": "Sono stati trovati dei duplicati dell'alias '{{alias}}'.
Gli alias di un dispositivo devono essere univoci all'interno della dashboard.", + "duplicate-alias-error": "Sono stati trovati dei duplicati dell'alias '{{alias}}'.
Gli alias di un dispositivo devono essere univoci all'interno della dashboard.", "configure-alias": "Configura alias '{{alias}}'", - "no-devices-matching": "Nessun dispositivo corrispondente a '{{entity}}' é stato trovato.", + "no-devices-matching": "Nessun dispositivo corrispondente a '{{entity}}' è stato trovato.", "alias": "Alias", - "alias-required": "Alias dispositivo richesto.", + "alias-required": "Alias dispositivo richiesto.", "remove-alias": "Rimuovi alias dispositivo", "add-alias": "Aggiungi alias dispositivo", "name-starts-with": "Dispositivo il cui nome inizia per", @@ -639,8 +661,8 @@ "accessTokenCopiedMessage": "Token di accesso del dispositivo copiato negli Appunti", "assignedToCustomer": "Assegnato al cliente", "unable-delete-device-alias-title": "Impossibile rimuovere l'alias del dispositivo", - "unable-delete-device-alias-text": "L'alias del dispositivo '{{deviceAlias}}' non può essere eliminato perchè utilizzato dai seguenti widget:
{{widgetsList}}", - "is-gateway": "E' un gateway", + "unable-delete-device-alias-text": "L'alias del dispositivo '{{deviceAlias}}' non può essere eliminato perché utilizzato dai seguenti widget:
{{widgetsList}}", + "is-gateway": "È un gateway", "public": "Pubblico", "device-public": "Il dispositivo è pubblico", "select-device": "Seleziona dispositivo" @@ -659,9 +681,9 @@ "aliases": "Alias entità", "entity-alias": "Alias entità", "unable-delete-entity-alias-title": "Impossibile eliminare alias entità", - "unable-delete-entity-alias-text": "L'alias dell'entità '{{entityAlias}}' non può essere eliminato perchè utilizzato dai seguenti widget:
{{widgetsList}}", - "duplicate-alias-error": "Trovato un duplicato dell'alias '{{alias}}'.
Gli alias dell'entità devono essere univoci all'interno della dashboard.", - "missing-entity-filter-error": "Filter is missing for alias '{{alias}}'.", + "unable-delete-entity-alias-text": "L'alias dell'entità '{{entityAlias}}' non può essere eliminato perché utilizzato dai seguenti widget:
{{widgetsList}}", + "duplicate-alias-error": "Trovato un duplicato dell'alias '{{alias}}'.
Gli alias dell'entità devono essere univoci all'interno della dashboard.", + "missing-entity-filter-error": "Manca il filtro per l'alias '{{alias}}'.", "configure-alias": "Configura '{{alias}}' alias", "alias": "Alias", "alias-required": "Alias entità obbligatorio.", @@ -701,6 +723,10 @@ "type-assets": "Asset", "list-of-assets": "{ count, plural, 1 {Un asset} other {Lista di # asset} }", "asset-name-starts-with": "Asset i cui nomi iniziano per '{{prefix}}'", + "type-entity-view": "Vista entità", + "type-entity-views": "Viste entità", + "list-of-entity-views": "{ count, plural, 1 {Una vista entità} other {Lista di # viste entità} }", + "entity-view-name-starts-with": "Viste entità i cui nomi iniziano per '{{prefix}}'", "type-rule": "Regola", "type-rules": "Regole", "list-of-rules": "{ count, plural, 1 {Una regola} other {Lista di # regole} }", @@ -711,7 +737,7 @@ "plugin-name-starts-with": "Plugin i cui nomi iniziano per '{{prefix}}'", "type-tenant": "Tenant", "type-tenants": "Tenants", - "list-of-tenants": "{ count, plural, 1 {One tenant} other {List of # tenants} }", + "list-of-tenants": "{ count, plural, 1 {One tenant} other {Lista di # tenants} }", "tenant-name-starts-with": "Tenants whose names start with '{{prefix}}'", "type-customer": "Cliente", "type-customers": "Clienti", @@ -719,7 +745,7 @@ "customer-name-starts-with": "Clienti i cui nomi iniziano per '{{prefix}}'", "type-user": "Utente", "type-users": "Utenti", - "list-of-users": "{ count, plural, 1 {Un utente} other {Lista of # utenti} }", + "list-of-users": "{ count, plural, 1 {Un utente} other {Lista di # utenti} }", "user-name-starts-with": "Utenti i cui nomi iniziano per '{{prefix}}'", "type-dashboard": "Dashboard", "type-dashboards": "Dashboard", @@ -730,16 +756,117 @@ "list-of-alarms": "{ count, plural, 1 {Un allarme} other {Lista di # allarmi} }", "alarm-name-starts-with": "Allarmi i cui nomi iniziano per '{{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-rulechains": "Rule chain", + "list-of-rulechains": "{ count, plural, 1 {Una rule chain} other {Lista di # catene di regole} }", + "rulechain-name-starts-with": "Catene di regole i cui nomi iniziano per '{{prefix}}'", + "type-rulenode": "Nodo regola", + "type-rulenodes": "Nodi regola", + "list-of-rulenodes": "{ count, plural, 1 {Un nodo regola} other {Lista di # nodi regola} }", + "rulenode-name-starts-with": "Nodi regola i cui nomi iniziano per '{{prefix}}'", "type-current-customer": "Cliente attuale", "search": "Ricerca entità", "selected-entities": "{ count, plural, 1 {1 entità selezionata} other {# entità selezionate} }", "entity-name": "Nome entità", "details": "Dettagli entità", "no-entities-prompt": "Nessuna entità trovata", - "no-data": "Nessun dato da mostrare" + "no-data": "Nessun dato da mostrare", + "columns-to-display": "Colonne da mostrare" + }, + "entity-view": { + "entity-view": "Vista entità", + "entity-view-required": "Vista entità richiesta.", + "entity-views": "Viste entità", + "management": "Gestione viste entità", + "view-entity-views": "Visualizza Viste entità", + "entity-view-alias": "Alias vista entità", + "aliases": "Alias vista entità", + "no-alias-matching": "'{{alias}}' non trovato.", + "no-aliases-found": "Nessun alias trovato.", + "no-key-matching": "'{{key}}' non trovata.", + "no-keys-found": "Nessuna chiave trovata.", + "create-new-alias": "Creane uno nuovo!", + "create-new-key": "Creane una nuova!", + "duplicate-alias-error": "Sono stati trovati dei duplicati dell'alias '{{alias}}'.
Gli alias di una vista entità devono essere univoci all'interno della dashboard.", + "configure-alias": "Configura alias '{{alias}}'", + "no-entity-views-matching": "Nessuna vista entità corrispondente a '{{entity}}' è stata trovato.", + "alias": "Alias", + "alias-required": "Alias vista entità richiesto.", + "remove-alias": "Rimuovi alias vista entità", + "add-alias": "Aggiungi alias vista entità", + "name-starts-with": "Vista entità il cui nome inizia per", + "entity-view-list": "Lista viste entità", + "use-entity-view-name-filter": "Usa filtro", + "entity-view-list-empty": "Nessuna vista entità selezionata.", + "entity-view-name-filter-required": "Filtro nome vista entità obbligatorio.", + "entity-view-name-filter-no-entity-view-matched": "Nessuna vista entità il cui nome inizia per '{{entity-view}}' è stata trovata.", + "add": "Aggiungi Vista entità", + "assign-to-customer": "Assegna al cliente", + "assign-entity-view-to-customer": "Assegna vista entità/viste entità al Cliente", + "assign-entity-view-to-customer-text": "Seleziona la vista entità da assegnare al cliente", + "no-entity-views-text": "Nessuna vista entità trovata", + "assign-to-customer-text": "Seleziona il cliente a cui assegnare la vista entità/le vista entità", + "entity-view-details": "Dettagli vista entità", + "add-entity-view-text": "Aggiungi nuova vista entità", + "delete": "Elimina vista entità", + "assign-entity-views": "Assegna viste entità", + "assign-entity-views-text": "Assegna { count, plural, 1 {1 vista entità} other {# viste entità} } al cliente", + "delete-entity-views": "Elimina viste entità", + "unassign-from-customer": "Annulla assegnazione al cliente", + "unassign-entity-views": "Annulla assegnazione viste entità", + "unassign-entity-views-action-title": "Annulla assegnazione { count, plural, 1 {1 vista entità} other {# viste entità} } al cliente", + "assign-new-entity-view": "Assegna nuova vista entità", + "delete-entity-view-title": "Sei sicuro di voler eliminare la vista entità '{{entity-viewName}}'?", + "delete-entity-view-text": "Attenzione, dopo la conferma la vista entità e tutti i suoi dati non saranno più recuperabili.", + "delete-entity-views-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 vista entità} other {# viste entità} }?", + "delete-entity-views-action-title": "Elimina { count, plural, 1 {1 vista entità} other {# viste entità} }", + "delete-entity-views-text": "Attenzione, dopo la conferma tutte le vista entità selezionati saranno eliminate e i relativi dati non saranno più recuperabili.", + "unassign-entity-view-title": "Sei sicuro di voler annullare l'assegnazione della vista entità '{{entity-viewName}}'?", + "unassign-entity-view-text": "Dopo la conferma sarà annullata l'assegnazione della vista entità e questa non sarà più accessibile dal cliente.", + "unassign-entity-view": "Annulla assegnazione vista entità", + "unassign-entity-views-title": "Sei sicuro di voler annullare l'assegnazione di { count, plural, 1 {1 vista entità} other {# viste entità} }?", + "unassign-entity-views-text": "Dopo la conferma sarà annullata l'assegnazione di tutte le vista entità selezionate e queste non saranno più accessibili dal cliente.", + "entity-view-type": "Tipo vista entità", + "entity-view-type-required": "Tipo vista entità obbligatorio.", + "select-entity-view-type": "Seleziona tipo vista entità", + "enter-entity-view-type": "Inserisci tipo vista entità", + "any-entity-view": "Qualsiasi vista entità", + "no-entity-view-types-matching": "Nessuna vista entità corrispondente a '{{entitySubtype}}' è stata trovata.", + "entity-view-type-list-empty": "Nessun tipo di vista entità selezionato.", + "entity-view-types": "Tipi vista entità", + "name": "Nome", + "name-required": "Nome obbligatorio.", + "description": "Descrizione", + "events": "Eventi", + "details": "Dettagli", + "copyId": "Copia Id vista entità", + "assignedToCustomer": "Assegnata al cliente", + "unable-entity-view-device-alias-title": "Impossibile rimuovere l'alias del vista entità", + "unable-entity-view-device-alias-text": "L'alias del vista entità '{{entity-viewAlias}}' non può essere eliminato perché utilizzato dai seguenti widget:
{{widgetsList}}", + "select-entity-view": "Seleziona vista entità", + "make-public": "Rendi pubblica la vista entità", + "make-private": "Rendi privata la vista entità", + "start-date": "Data inizio", + "start-ts": "Ora inizio", + "end-date": "Data fine", + "end-ts": "Ora fine", + "date-limits": "Limiti temporali", + "client-attributes": "Attributi cliente", + "shared-attributes": "Attributi condivisi", + "server-attributes": "Attributi server", + "timeseries": "Serie temporali", + "client-attributes-placeholder": "Attributi cliente", + "shared-attributes-placeholder": "Attributi condivisi", + "server-attributes-placeholder": "Attributi server", + "timeseries-placeholder": "Serie temporali", + "target-entity": "Entità target", + "attributes-propagation": "Propagazione degli attributi", + "attributes-propagation-hint": "La vista entità copierà automaticamente gli attributi specificati dall'entità target ogni volta che questa vista entità sarà salvata e aggiornata. Per ragioni di performance, gli attributi dell'entità target non sono propagati alle viste entità ogni cambiamento di attributo. È possibile abilitare la propagazione automatica configurando il nodo regola \"Copia alla vista\" nella rule chain e collegando i messaggi \"Post attributes\" a \"Attributes Updated\" al nuovo nodo regola.", + "timeseries-data": "Dati delle serie temporali", + "timeseries-data-hint": "Imposta le chiavi delle serie temporali dell'entità target che saranno accessibili alla vista entità. Questi dati sono di sola lettura.", + "make-public-entity-view-title": "Sei sicuro di voler rendere pubblica la vista entità '{{entity-viewName}}'?", + "make-public-entity-view-text": "Dopo la conferma la vista entità e tutti i suoi dati saranno resi pubblici e accessibili dagli altri.", + "make-private-entity-view-title": "Sei sicuro di voler rendere privata la vista entità '{{entity-viewName}}'?", + "make-private-entity-view-text": "Dopo la conferma la vista entità e tutti i suoi dati saranno resi privati e non più accessibili da altri utenti." }, "event": { "event-type": "Tipo evento", @@ -795,8 +922,8 @@ "token": "Token di sicurezza", "add-converter": "Aggiungi convertitore", "add-config": "Aggiungi configurazione convertitore", - "device-name-expression": "Device name expression", - "device-type-expression": "Device type expression", + "device-name-expression": "Espressione nome dispositivo", + "device-type-expression": "Espressione tipo dispositivo", "custom": "Custom", "to-double": "To Double", "transformer": "Transformer", @@ -817,7 +944,7 @@ "credentials": "Credenziali", "username": "Nome utente", "password": "Password", - "retry-interval": "Retry interval in milliseconds", + "retry-interval": "Intervallo di ripetizione in millisecondi", "anonymous": "Anonimo", "basic": "Basic", "pem": "PEM", @@ -886,6 +1013,8 @@ "modbus-add-server": "Aggiungi server/slave", "modbus-add-server-prompt": "Aggiungi server/slave", "modbus-transport": "Transport", + "modbus-tcp-reconnect": "Riconnessione automatica", + "modbus-rtu-over-tcp": "RTU over TCP", "modbus-port-name": "Nome porta seriale", "modbus-encoding": "Codifica", "modbus-parity": "Parità", @@ -1077,9 +1206,9 @@ "name-required": "Nome obbligatorio.", "description": "Descrizione", "add": "Aggiungi 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.", + "set-root": "Imposta la rule chain come root", + "set-root-rulechain-title": "Sei sicuro di voler impostare la rule chain '{{ruleChainName}}' come root?", + "set-root-rulechain-text": "Dopo la conferma la rule chain diverrà root a gestirà tutti i messaggi in arrivo.", "delete-rulechain-title": "Sei sicuro di voler eliminare la rule chain '{{ruleChainName}}'?", "delete-rulechain-text": "Attenzione, dopo la conferma la rule chain e tutti i dati relativi non saranno più recuperabili.", "delete-rulechains-title": "Sei sicuro di voler eliminare { count, plural, 1 {1 rule chain} other {# rule chain} }?", @@ -1110,33 +1239,38 @@ "events": "Eventi", "search": "Ricerca nodi", "open-node-library": "Apri libreria nodi", - "add": "Add rule node", + "add": "Aggiungi nodo regola", "name": "Nome", "name-required": "Nome obbligatorio.", "type": "Tipo", "description": "Descrizione", - "delete": "Delete rule node", + "delete": "Elimina nodo regola", "select-all-objects": "Seleziona tutti i nodi e le connessioni", - "deselect-all-objects": "Deselect all nodes and connections", + "deselect-all-objects": "Deseleziona tutti i nodi e le connessioni", "delete-selected-objects": "Cancella nodi e connessioni selezionate", - "delete-selected": "Delete selected", + "delete-selected": "Elimina selezionati", "select-all": "Seleziona tutto", "copy-selected": "Copia selezionata", "deselect-all": "Deseleziona tutto", - "rulenode-details": "Rule node details", + "rulenode-details": "Dettagli nodo regola", "debug-mode": "Modalità debug", "configuration": "Configurazione", "link": "Link", - "link-details": "Rule node link details", + "link-details": "Dettagli link nodo regola", "add-link": "Aggiungi link", "link-label": "Etichetta link", "link-label-required": "Etichetta link obbligatoria.", - "custom-link-label": "Custom link label", - "custom-link-label-required": "Custom link label is required.", + "custom-link-label": "Etichetta link personalizzata", + "custom-link-label-required": "Etichetta link personalizzata obbligatoria.", + "link-labels": "Etichette link", + "link-labels-required": "Etichette link richieste.", + "no-link-labels-found": "Nessuna etichetta link trovata.", + "no-link-label-matching": "'{{label}}' non trovata.", + "create-new-link-label": "Creane una nuova!", "type-filter": "Filtro", - "type-filter-details": "Filter incoming messages with configured conditions", + "type-filter-details": "Filtra i messaggi in arrivo con le condizioni configurate", "type-enrichment": "Enrichment", - "type-enrichment-details": "Add additional information into Message Metadata", + "type-enrichment-details": "Aggiungi informazioni addizionali nei metadati del messaggio", "type-transformation": "Transformation", "type-transformation-details": "Change Message payload and Metadata", "type-action": "Azioni", @@ -1147,12 +1281,15 @@ "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", + "type-unknown": "Sconosciuto", + "type-unknown-details": "Nodo regola non trovato", "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": "Messaggio", "message-type": "Tipo messaggio", + "select-message-type": "Seleziona tipo messaggio", "message-type-required": "Tipo messaggio obbligatorio", "metadata": "Metadata", "metadata-required": "Metadata entries can't be empty.", @@ -1200,13 +1337,13 @@ }, "timewindow": { "days": "{ days, plural, 1 { giorno } other {# giorni } }", - "hours": "{ hours, plural, 0 { hour } 1 {1 ora } other {# ore } }", - "minutes": "{ minutes, plural, 0 { minute } 1 {1 minuto } other {# minuti } }", - "seconds": "{ seconds, plural, 0 { second } 1 {1 secondo } other {# secondi } }", + "hours": "{ hours, plural, 0 { ora } 1 {1 ora } other {# ore } }", + "minutes": "{ minutes, plural, 0 { minuto } 1 {1 minuto } other {# minuti } }", + "seconds": "{ seconds, plural, 0 { secondo } 1 {1 secondo } other {# secondi } }", "realtime": "Realtime", "history": "Cronologia", "last-prefix": "ultimo", - "period": "from {{ startTime }} to {{ endTime }}", + "period": "da {{ startTime }} a {{ endTime }}", "edit": "Modifica intervallo temporale", "date-range": "Intervallo date", "last": "Ultimo", @@ -1215,7 +1352,7 @@ "user": { "user": "Utente", "users": "Utenti", - "customer-users": "Customer Users", + "customer-users": "Utente cliente", "tenant-admins": "Amministratori Tenant", "sys-admin": "Amministratore di sistema", "tenant-admin": "Amministratore tenant", @@ -1232,7 +1369,7 @@ "delete-users-action-title": "Elimina { count, plural, 1 {1 utente} other {# utenti} }", "delete-users-text": "Attenzione, dopo la conferma tutti gli utenti selezionati saranno eliminati e tutti i relativi dati non saranno più recuperabili.", "activation-email-sent-message": "Email di attivazione inviata con successo!", - "resend-activation": "Resend activation", + "resend-activation": "Invia di nuovo attivazione", "email": "Email", "email-required": "Email obbligatoria.", "invalid-email-format": "Formato email non valido.", @@ -1251,7 +1388,9 @@ "activation-link-text": "Per attivare l'utente utilizza il seguente link di attivazione :", "copy-activation-link": "Copia link di attivazione", "activation-link-copied-message": "Link di attivazione utente copiato negli appunti", - "details": "Dettagli" + "details": "Dettagli", + "login-as-tenant-admin": "Accedi come Amministratore tenant", + "login-as-customer-user": "Accedi come Utente cliente" }, "value": { "type": "Tipo valore", @@ -1274,7 +1413,7 @@ "select-widgets-bundle": "Seleziona bundle widget", "management": "Gestione widget", "editor": "Editor Widget", - "widget-type-not-found": "Problem loading widget configuration.
Probably associated\n widget type was removed.", + "widget-type-not-found": "Problem loading widget configuration.
Probably associated\n widget type was removed.", "widget-type-load-error": "Widget non caricato a causa dei seguenti errori:", "remove": "Elimina widget", "edit": "Modifica widget", @@ -1295,7 +1434,7 @@ "saveAs": "Salva widget come", "save-widget-type-as": "Salva tipo widget come", "save-widget-type-as-text": "Please enter new widget title and/or select target widgets bundle", - "toggle-fullscreen": "Toggle fullscreen", + "toggle-fullscreen": "Commuta modalità schermo intero", "run": "Esegui widget", "title": "Titolo widget", "title-required": "Titolo widget obbligatorio.", @@ -1308,7 +1447,7 @@ "tidy": "Tidy", "css": "CSS", "settings-schema": "Impostazioni schema", - "datakey-settings-schema": "Data key settings schema", + "datakey-settings-schema": "Impostazioni Data key schema", "javascript": "Javascript", "remove-widget-type-title": "Sei sicuro di voler rimuovere il tipo di widget '{{widgetName}}'?", "remove-widget-type-text": "Dopo la conferma il tipo di widget e tutti i suoi dati non saranno più recuperabili.", @@ -1367,7 +1506,7 @@ "general-settings": "Impostazioni generali", "display-title": "Mostra titolo", "drop-shadow": "Drop shadow", - "enable-fullscreen": "Abilita fullscreen", + "enable-fullscreen": "Abilita schermo intero", "background-color": "Colore sfondo", "text-color": "Colore testo", "padding": "Padding", @@ -1412,7 +1551,7 @@ "export": "Esporta un tipo di widget", "export-failed-error": "Impossibile esportare il tipo di widget: {{error}}", "create-new-widget-type": "Crea un nuovo tipo di widget", - "widget-type-file": "Widget type file", + "widget-type-file": "File tipo di widget", "invalid-widget-type-file-error": "Impossibile importare un tipo di widget: struttura dati del widget non valida." }, "icon": { @@ -1423,11 +1562,11 @@ }, "custom": { "widget-action": { - "action-cell-button": "Action cell button", - "row-click": "On row click", - "polygon-click": "On polygon click", - "marker-click": "On marker click", - "tooltip-tag-action": "Tooltip tag action" + "action-cell-button": "Pulsante azione cella", + "row-click": "Click sulla riga", + "polygon-click": "Click sul poligono", + "marker-click": "Click sul marker", + "tooltip-tag-action": "Azione tooltip" } }, "language": { @@ -1436,9 +1575,9 @@ "de_DE": "Tedesco", "fr_FR": "Francese", "zh_CN": "Cinese", - "ko_KR": "Coreano", "en_US": "Inglese", "it_IT": "Italiano", + "ko_KR": "Coreano", "ru_RU": "Russo", "es_ES": "Spagnolo", "ja_JA": "Giapponese", @@ -1446,4 +1585,4 @@ "fa_IR": "Persiana" } } -} \ No newline at end of file +} diff --git a/ui/src/app/widget/lib/map-widget2.js b/ui/src/app/widget/lib/map-widget2.js index 42e9cdb463..4762a3fda1 100644 --- a/ui/src/app/widget/lib/map-widget2.js +++ b/ui/src/app/widget/lib/map-widget2.js @@ -305,12 +305,9 @@ export default class TbMapWidgetV2 { } function updateLocationPolygonColor(location, color) { - if (!location.settings.calculatedPolygonColor || location.settings.calculatedPolygonColor !== color) { + if (location.polygon && color) { location.settings.calculatedPolygonColor = color; - if (location.polygon) { - tbMap.map.updatePolygonColor(location.polygon, location.settings, color); - } - + tbMap.map.updatePolygonColor(location.polygon, location.settings, color); } } @@ -338,10 +335,8 @@ export default class TbMapWidgetV2 { function updateLocationStyle(location, dataMap) { updateLocationLabel(location, dataMap); var color = calculateLocationColor(location, dataMap); - var polygonColor = calculateLocationPolygonColor(location, dataMap); var image = calculateLocationMarkerImage(location, dataMap); updateLocationColor(location, color, image); - if (location.settings.usePolygonColorFunction) updateLocationPolygonColor(location, polygonColor); updateLocationMarkerIcon(location, image); } @@ -441,6 +436,7 @@ export default class TbMapWidgetV2 { if (location.marker) { updateLocationStyle(location, dataMap); } + } } return locationChanged; @@ -456,11 +452,13 @@ export default class TbMapWidgetV2 { locationPolygonClick(event, location); }, [location.dsIndex]); tbMap.polygons.push(location.polygon); + if (location.settings.usePolygonColorFunction) updateLocationPolygonColor(location, calculateLocationPolygonColor(location, dataMap)); } else if (polygonLatLngs.length > 0) { let prevPolygonArr = tbMap.map.getPolygonLatLngs(location.polygon); if (!prevPolygonArr || !arraysEqual(prevPolygonArr, polygonLatLngs)) { tbMap.map.setPolygonLatLngs(location.polygon, polygonLatLngs); } + if (location.settings.usePolygonColorFunction) updateLocationPolygonColor(location, calculateLocationPolygonColor(location, dataMap)); } } } diff --git a/ui/webpack.config.prod.js b/ui/webpack.config.prod.js index f7093e7273..446b48a848 100644 --- a/ui/webpack.config.prod.js +++ b/ui/webpack.config.prod.js @@ -96,7 +96,7 @@ module.exports = { new CompressionPlugin({ asset: "[path].gz[query]", algorithm: "gzip", - test: /\.js$|\.css$|\.svg$|\.ttf$|\.woff$|\.woff2|\.eot$\.json$/, + test: /\.js$|\.css$|\.svg$|\.ttf$|\.woff$|\.woff2$|\.eot$|\.json$/, threshold: 10240, minRatio: 0.8 }),