diff --git a/application/src/main/data/json/system/widget_bundles/charts.json b/application/src/main/data/json/system/widget_bundles/charts.json index 2772c696bf..de32604dbb 100644 --- a/application/src/main/data/json/system/widget_bundles/charts.json +++ b/application/src/main/data/json/system/widget_bundles/charts.json @@ -54,7 +54,7 @@ }, { "alias": "pie", - "name": "Pie- Flot", + "name": "Pie - Flot", "image": "data:image/png;base64,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", "description": "Displays latest values of the attributes or timeseries data for multiple entities in a pie chart. Supports numeric values only.", "descriptor": { @@ -69,7 +69,7 @@ "dataKeySettingsSchema": "{}\n", "settingsDirective": "tb-flot-pie-widget-settings", "dataKeySettingsDirective": "tb-flot-pie-key-settings", - "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.6114638304362894,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.9955906536344441,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.9430835931647599,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"radius\":1,\"fontColor\":\"#545454\",\"fontSize\":10,\"decimals\":1,\"legend\":{\"show\":true,\"position\":\"nw\",\"labelBoxBorderColor\":\"#CCCCCC\",\"backgroundColor\":\"#F0F0F0\",\"backgroundOpacity\":0.85},\"innerRadius\":0,\"showLabels\":true,\"showPercentages\":true,\"stroke\":{\"width\":5},\"tilt\":1,\"animatedPie\":false},\"title\":\"Pie- Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" + "defaultConfig": "{\"datasources\":[{\"type\":\"function\",\"name\":\"function\",\"dataKeys\":[{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"First\",\"color\":\"#2196f3\",\"settings\":{},\"_hash\":0.15479322438769105,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Second\",\"color\":\"#4caf50\",\"settings\":{},\"_hash\":0.6114638304362894,\"funcBody\":\"var value = (prevValue-20) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+20;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Third\",\"color\":\"#f44336\",\"settings\":{},\"_hash\":0.9955906536344441,\"funcBody\":\"var value = (prevValue-40) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+40;\"},{\"name\":\"f(x)\",\"type\":\"function\",\"label\":\"Fourth\",\"color\":\"#ffc107\",\"settings\":{},\"_hash\":0.9430835931647599,\"funcBody\":\"var value = (prevValue-50) + Math.random() * 2 - 1;\\nif (value < 0) {\\n\\tvalue = 0;\\n} else if (value > 100) {\\n\\tvalue = 100;\\n}\\nreturn value+50;\"}]}],\"timewindow\":{\"realtime\":{\"timewindowMs\":60000}},\"showTitle\":true,\"backgroundColor\":\"#fff\",\"color\":\"rgba(0, 0, 0, 0.87)\",\"padding\":\"8px\",\"settings\":{\"radius\":1,\"fontColor\":\"#545454\",\"fontSize\":10,\"decimals\":1,\"legend\":{\"show\":true,\"position\":\"nw\",\"labelBoxBorderColor\":\"#CCCCCC\",\"backgroundColor\":\"#F0F0F0\",\"backgroundOpacity\":0.85},\"innerRadius\":0,\"showLabels\":true,\"showPercentages\":true,\"stroke\":{\"width\":5},\"tilt\":1,\"animatedPie\":false},\"title\":\"Pie - Flot\",\"dropShadow\":true,\"enableFullscreen\":true,\"titleStyle\":{\"fontSize\":\"16px\",\"fontWeight\":400}}" } }, { diff --git a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java index d0d5f37e00..306102c66c 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/SqlDatabaseUpgradeService.java @@ -571,6 +571,22 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", SCHEMA_UPDATE_SQL); loadSql(schemaUpdateFile, conn); + log.info("Loading queues..."); + try { + if (!CollectionUtils.isEmpty(queueConfig.getQueues())) { + queueConfig.getQueues().forEach(queueSettings -> { + Queue queue = queueConfigToQueue(queueSettings); + Queue existing = queueService.findQueueByTenantIdAndName(queue.getTenantId(), queue.getName()); + if (existing == null) { + queueService.saveQueue(queue); + } + }); + } else { + systemDataLoaderService.createQueues(); + } + } catch (Exception e) { + } + log.info("Updating device profiles..."); schemaUpdateFile = Paths.get(installScripts.getDataDir(), "upgrade", "3.3.4", "schema_update_device_profile.sql"); loadSql(schemaUpdateFile, conn); @@ -628,4 +644,29 @@ public class SqlDatabaseUpgradeService implements DatabaseEntitiesUpgradeService return isOldSchema; } + private Queue queueConfigToQueue(TbRuleEngineQueueConfiguration queueSettings) { + Queue queue = new Queue(); + queue.setTenantId(TenantId.SYS_TENANT_ID); + queue.setName(queueSettings.getName()); + queue.setTopic(queueSettings.getTopic()); + queue.setPollInterval(queueSettings.getPollInterval()); + queue.setPartitions(queueSettings.getPartitions()); + queue.setPackProcessingTimeout(queueSettings.getPackProcessingTimeout()); + SubmitStrategy submitStrategy = new SubmitStrategy(); + submitStrategy.setBatchSize(queueSettings.getSubmitStrategy().getBatchSize()); + submitStrategy.setType(SubmitStrategyType.valueOf(queueSettings.getSubmitStrategy().getType())); + queue.setSubmitStrategy(submitStrategy); + ProcessingStrategy processingStrategy = new ProcessingStrategy(); + processingStrategy.setType(ProcessingStrategyType.valueOf(queueSettings.getProcessingStrategy().getType())); + processingStrategy.setRetries(queueSettings.getProcessingStrategy().getRetries()); + processingStrategy.setFailurePercentage(queueSettings.getProcessingStrategy().getFailurePercentage()); + processingStrategy.setPauseBetweenRetries(queueSettings.getProcessingStrategy().getPauseBetweenRetries()); + processingStrategy.setMaxPauseBetweenRetries(queueSettings.getProcessingStrategy().getMaxPauseBetweenRetries()); + queue.setProcessingStrategy(processingStrategy); + queue.setConsumerPerPartition(queueSettings.isConsumerPerPartition()); + return queue; + } + + + } diff --git a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java index 7b87668319..e27f2e88c2 100644 --- a/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java +++ b/application/src/main/java/org/thingsboard/server/service/install/update/DefaultDataUpdateService.java @@ -162,21 +162,6 @@ public class DefaultDataUpdateService implements DataUpdateService { break; case "3.3.4": log.info("Updating data from version 3.3.4 to 3.4.0 ..."); - log.info("Loading queues..."); - try { - if (!CollectionUtils.isEmpty(queueConfig.getQueues())) { - queueConfig.getQueues().forEach(queueSettings -> { - Queue queue = queueConfigToQueue(queueSettings); - Queue existing = queueService.findQueueByTenantIdAndName(queue.getTenantId(), queue.getName()); - if (existing == null) { - queueService.saveQueue(queue); - } - }); - } else { - systemDataLoaderService.createQueues(); - } - } catch (Exception e) { - } tenantsProfileQueueConfigurationUpdater.updateEntities(null); checkPointRuleNodesUpdater.updateEntities(null); break; @@ -649,29 +634,6 @@ public class DefaultDataUpdateService implements DataUpdateService { return mainQueueConfiguration; } - private Queue queueConfigToQueue(TbRuleEngineQueueConfiguration queueSettings) { - Queue queue = new Queue(); - queue.setTenantId(TenantId.SYS_TENANT_ID); - queue.setName(queueSettings.getName()); - queue.setTopic(queueSettings.getTopic()); - queue.setPollInterval(queueSettings.getPollInterval()); - queue.setPartitions(queueSettings.getPartitions()); - queue.setPackProcessingTimeout(queueSettings.getPackProcessingTimeout()); - SubmitStrategy submitStrategy = new SubmitStrategy(); - submitStrategy.setBatchSize(queueSettings.getSubmitStrategy().getBatchSize()); - submitStrategy.setType(SubmitStrategyType.valueOf(queueSettings.getSubmitStrategy().getType())); - queue.setSubmitStrategy(submitStrategy); - ProcessingStrategy processingStrategy = new ProcessingStrategy(); - processingStrategy.setType(ProcessingStrategyType.valueOf(queueSettings.getProcessingStrategy().getType())); - processingStrategy.setRetries(queueSettings.getProcessingStrategy().getRetries()); - processingStrategy.setFailurePercentage(queueSettings.getProcessingStrategy().getFailurePercentage()); - processingStrategy.setPauseBetweenRetries(queueSettings.getProcessingStrategy().getPauseBetweenRetries()); - processingStrategy.setMaxPauseBetweenRetries(queueSettings.getProcessingStrategy().getMaxPauseBetweenRetries()); - queue.setProcessingStrategy(processingStrategy); - queue.setConsumerPerPartition(queueSettings.isConsumerPerPartition()); - return queue; - } - private final PaginatedUpdater checkPointRuleNodesUpdater = new PaginatedUpdater<>() { diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index eab9aafd00..bf23870aa0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -706,6 +706,7 @@ transport: bind_address: "${COAP_BIND_ADDRESS:0.0.0.0}" bind_port: "${COAP_BIND_PORT:5683}" timeout: "${COAP_TIMEOUT:10000}" + piggyback_timeout: "${COAP_PIGGYBACK_TIMEOUT:500}" psm_activity_timer: "${COAP_PSM_ACTIVITY_TIMER:10000}" paging_transmission_window: "${COAP_PAGING_TRANSMISSION_WINDOW:10000}" dtls: diff --git a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java index e815378d27..61bb53b060 100644 --- a/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java +++ b/application/src/test/java/org/thingsboard/server/edge/BaseEdgeTest.java @@ -58,6 +58,8 @@ import org.thingsboard.server.common.data.device.profile.AlarmRule; import org.thingsboard.server.common.data.device.profile.AllowCreateNewDevicesDeviceProfileProvisionConfiguration; import org.thingsboard.server.common.data.device.profile.DeviceProfileAlarm; import org.thingsboard.server.common.data.device.profile.DeviceProfileData; +import org.thingsboard.server.common.data.device.profile.JsonTransportPayloadConfiguration; +import org.thingsboard.server.common.data.device.profile.MqttDeviceProfileTransportConfiguration; import org.thingsboard.server.common.data.device.profile.SimpleAlarmConditionSpec; import org.thingsboard.server.common.data.edge.Edge; import org.thingsboard.server.common.data.edge.EdgeEvent; @@ -199,7 +201,11 @@ abstract public class BaseEdgeTest extends AbstractControllerTest { private void installation() throws Exception { edge = doPost("/api/edge", constructEdge("Test Edge", "test"), Edge.class); - DeviceProfile deviceProfile = this.createDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME); + MqttDeviceProfileTransportConfiguration transportConfiguration = new MqttDeviceProfileTransportConfiguration(); + transportConfiguration.setTransportPayloadTypeConfiguration(new JsonTransportPayloadConfiguration()); + + DeviceProfile deviceProfile = this.createDeviceProfile(CUSTOM_DEVICE_PROFILE_NAME, transportConfiguration); + extendDeviceProfileData(deviceProfile); doPost("/api/deviceProfile", deviceProfile, DeviceProfile.class); diff --git a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java index 74738c361f..cea08003bf 100644 --- a/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/cluster/routing/HashPartitionServiceTest.java @@ -85,7 +85,9 @@ public class HashPartitionServiceTest { .addAllServiceTypes(Collections.singletonList(ServiceType.TB_CORE.name())) .build()); } + clusterRoutingService.init(); + clusterRoutingService.partitionsInit(); clusterRoutingService.recalculatePartitions(currentServer, otherServers); } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerContext.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerContext.java index dda014da4c..8b448a1bcd 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerContext.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerContext.java @@ -38,6 +38,10 @@ public class CoapServerContext { @Value("${transport.coap.timeout}") private Long timeout; + @Getter + @Value("${transport.coap.piggyback_timeout}") + private Long piggybackTimeout; + @Getter @Value("${transport.coap.psm_activity_timer:10000}") private long psmActivityTimer; diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java index 8dbbc5a620..8d38b67d9c 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/CoapServerService.java @@ -29,4 +29,6 @@ public interface CoapServerService { long getTimeout(); + long getPiggybackTimeout(); + } diff --git a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java index 3aa0d0c122..b7b0bcb436 100644 --- a/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java +++ b/common/coap-server/src/main/java/org/thingsboard/server/coapserver/DefaultCoapServerService.java @@ -88,6 +88,11 @@ public class DefaultCoapServerService implements CoapServerService { return coapServerContext.getTimeout(); } + @Override + public long getPiggybackTimeout() { + return coapServerContext.getPiggybackTimeout(); + } + private CoapServer createCoapServer() throws UnknownHostException { Configuration networkConfig = new Configuration(); networkConfig.set(CoapConfig.BLOCKWISE_STRICT_BLOCK2_OPTION, true); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java index 36cbda47c3..f432862499 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/DeviceProfile.java @@ -16,6 +16,7 @@ package org.thingsboard.server.common.data; import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.core.JsonProcessingException; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; @@ -78,6 +79,8 @@ public class DeviceProfile extends SearchTextBased implements H "If present, the specified queue will be used to store all unprocessed messages related to device, including telemetry, attribute updates, etc. " + "Otherwise, the 'Main' queue will be used to store those messages.") private QueueId defaultQueueId; + + private String defaultQueueName; @Valid private transient DeviceProfileData profileData; @JsonIgnore @@ -168,4 +171,13 @@ public class DeviceProfile extends SearchTextBased implements H } } + @JsonIgnore + public String getDefaultQueueName() { + return defaultQueueName; + } + + @JsonProperty + public void setDefaultQueueName(String defaultQueueName) { + this.defaultQueueName = defaultQueueName; + } } diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/TransportPayloadTypeConfiguration.java b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/TransportPayloadTypeConfiguration.java index 7129ba8846..4d229a3706 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/TransportPayloadTypeConfiguration.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/device/profile/TransportPayloadTypeConfiguration.java @@ -21,6 +21,8 @@ import com.fasterxml.jackson.annotation.JsonSubTypes; import com.fasterxml.jackson.annotation.JsonTypeInfo; import org.thingsboard.server.common.data.TransportPayloadType; +import java.io.Serializable; + @JsonIgnoreProperties(ignoreUnknown = true) @JsonTypeInfo( use = JsonTypeInfo.Id.NAME, @@ -29,7 +31,7 @@ import org.thingsboard.server.common.data.TransportPayloadType; @JsonSubTypes({ @JsonSubTypes.Type(value = JsonTransportPayloadConfiguration.class, name = "JSON"), @JsonSubTypes.Type(value = ProtoTransportPayloadConfiguration.class, name = "PROTOBUF")}) -public interface TransportPayloadTypeConfiguration { +public interface TransportPayloadTypeConfiguration extends Serializable { @JsonIgnore TransportPayloadType getTransportPayloadType(); diff --git a/common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java b/common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java index b0bbfa3dc6..c8583527f1 100644 --- a/common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java +++ b/common/message/src/test/java/org/thingsboard/server/common/msg/tools/RateLimitsTest.java @@ -67,7 +67,7 @@ public class RateLimitsTest { assertThat(rateLimits.tryConsume()).as("new token is available").isFalse(); int expectedRefillTime = period * 1000; - int gap = 300; + int gap = 500; await("tokens refill for rate limit " + rateLimitConfig) .atLeast(expectedRefillTime - gap, TimeUnit.MILLISECONDS) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java index 8a56a86bcc..3317e75c91 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/HashPartitionService.java @@ -90,20 +90,37 @@ public class HashPartitionService implements PartitionService { @PostConstruct public void init() { this.hashFunction = forName(hashFunctionName); + QueueKey coreKey = new QueueKey(ServiceType.TB_CORE); + partitionSizesMap.put(coreKey, corePartitions); + partitionTopicsMap.put(coreKey, coreTopic); + + if (!isTransport(serviceInfoProvider.getServiceType())) { + doInitRuleEnginePartitions(); + } } @AfterStartUp(order = AfterStartUp.QUEUE_INFO_INITIALIZATION) public void partitionsInit() { - QueueKey coreKey = new QueueKey(ServiceType.TB_CORE); - partitionSizesMap.put(coreKey, corePartitions); - partitionTopicsMap.put(coreKey, coreTopic); + if (isTransport(serviceInfoProvider.getServiceType())) { + doInitRuleEnginePartitions(); + } + } - List queueRoutingInfoList; + private void doInitRuleEnginePartitions() { + List queueRoutingInfoList = getQueueRoutingInfos(); + queueRoutingInfoList.forEach(queue -> { + QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue); + partitionTopicsMap.put(queueKey, queue.getQueueTopic()); + partitionSizesMap.put(queueKey, queue.getPartitions()); + queuesById.put(queue.getQueueId(), queue); + }); + } + private List getQueueRoutingInfos() { + List queueRoutingInfoList; String serviceType = serviceInfoProvider.getServiceType(); - - if ("tb-transport".equals(serviceType)) { + if (isTransport(serviceType)) { //If transport started earlier than tb-core int getQueuesRetries = 10; while (true) { @@ -128,13 +145,11 @@ public class HashPartitionService implements PartitionService { } else { queueRoutingInfoList = queueRoutingInfoService.getAllQueuesRoutingInfo(); } + return queueRoutingInfoList; + } - queueRoutingInfoList.forEach(queue -> { - QueueKey queueKey = new QueueKey(ServiceType.TB_RULE_ENGINE, queue); - partitionTopicsMap.put(queueKey, queue.getQueueTopic()); - partitionSizesMap.put(queueKey, queue.getPartitions()); - queuesById.put(queue.getQueueId(), queue); - }); + private boolean isTransport(String serviceType) { + return "tb-transport".equals(serviceType); } @Override diff --git a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java index 3e291a8177..0016cc05d8 100644 --- a/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java +++ b/common/transport/coap/src/main/java/org/thingsboard/server/transport/coap/CoapTransportResource.java @@ -69,6 +69,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { private final ConcurrentMap dtlsSessionsMap; private final long timeout; + private final long piggybackTimeout; private final CoapClientContext clients; public CoapTransportResource(CoapTransportContext ctx, CoapServerService coapServerService, String name) { @@ -77,6 +78,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { this.addObserver(new CoapResourceObserver()); this.dtlsSessionsMap = coapServerService.getDtlsSessionsMap(); this.timeout = coapServerService.getTimeout(); + this.piggybackTimeout = coapServerService.getPiggybackTimeout(); this.clients = ctx.getClientContext(); long sessionReportTimeout = ctx.getSessionReportTimeout(); ctx.getScheduler().scheduleAtFixedRate(clients::reportActivity, new Random().nextInt((int) sessionReportTimeout), sessionReportTimeout, TimeUnit.MILLISECONDS); @@ -169,7 +171,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { } private void processProvision(CoapExchange exchange) { - exchange.accept(); + deferAccept(exchange); try { UUID sessionId = UUID.randomUUID(); log.trace("[{}] Processing provision publish msg [{}]!", sessionId, exchange.advanced().getRequest()); @@ -195,7 +197,7 @@ public class CoapTransportResource extends AbstractCoapTransportResource { private void processRequest(CoapExchange exchange, SessionMsgType type) { log.trace("Processing {}", exchange.advanced().getRequest()); - exchange.accept(); + deferAccept(exchange); Exchange advanced = exchange.advanced(); Request request = advanced.getRequest(); @@ -346,6 +348,20 @@ public class CoapTransportResource extends AbstractCoapTransportResource { new CoapNoOpCallback(exchange)); } + /** + * Send an empty ACK if we are unable to send the full response within the timeout. + * If the full response is transmitted before the timeout this will not do anything. + * If this is triggered the full response will be sent in a separate CON/NON message. + * Essentially this allows the use of piggybacked responses. + */ + private void deferAccept(CoapExchange exchange) { + if (piggybackTimeout > 0) { + transportContext.getScheduler().schedule(exchange::accept, piggybackTimeout, TimeUnit.MILLISECONDS); + } else { + exchange.accept(); + } + } + private UUID toSessionId(TransportProtos.SessionInfoProto sessionInfoProto) { return new UUID(sessionInfoProto.getSessionIdMSB(), sessionInfoProto.getSessionIdLSB()); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java index 04084de987..df5a49c1e1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java +++ b/dao/src/main/java/org/thingsboard/server/dao/device/DeviceProfileServiceImpl.java @@ -37,8 +37,10 @@ import org.thingsboard.server.common.data.id.DeviceProfileId; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.page.PageData; import org.thingsboard.server.common.data.page.PageLink; +import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.dao.entity.AbstractCachedEntityService; import org.thingsboard.server.dao.exception.DataValidationException; +import org.thingsboard.server.dao.queue.QueueService; import org.thingsboard.server.dao.service.DataValidator; import org.thingsboard.server.dao.service.PaginatedRemover; import org.thingsboard.server.dao.service.Validator; @@ -71,6 +73,9 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService deviceProfileValidator; + @Autowired + private QueueService queueService; + private final Lock findOrCreateLock = new ReentrantLock(); @TransactionalEventListener(classes = DeviceProfileEvictEvent.class) @@ -119,6 +124,12 @@ public class DeviceProfileServiceImpl extends AbstractCachedEntityService -
+ admin.queue-name diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss index c42c4d714d..13128ad29a 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.scss @@ -17,6 +17,10 @@ .queue-strategy { padding-bottom: 16px; + .mat-expansion-panel-header { + height: 50px; + } + .mat-expansion-panel-body { padding-bottom: 0 !important; } diff --git a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts index bb86b1edcb..b84dfc9985 100644 --- a/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts +++ b/ui-ngx/src/app/modules/home/components/queue/queue-form.component.ts @@ -158,6 +158,8 @@ export class QueueFormComponent implements ControlValueAccessor, OnInit, OnDestr this.modelValue = value; if (isDefinedAndNotNull(this.modelValue)) { this.queueFormGroup.patchValue(this.modelValue, {emitEvent: false}); + this.queueFormGroup.get('additionalInfo').get('description') + .patchValue(this.modelValue.additionalInfo?.description, {emitEvent: false}); this.submitStrategyTypeChanged(); } if (!this.disabled && !this.queueFormGroup.valid) { diff --git a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts index 7aa0f6933e..a76a65ab96 100644 --- a/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/dynamic-widget.component.ts @@ -38,6 +38,7 @@ import { EntityRelationService } from '@core/http/entity-relation.service'; import { EntityService } from '@core/http/entity.service'; import { DialogService } from '@core/services/dialog.service'; import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service'; +import { ResourceService } from '@core/http/resource.service'; import { DatePipe } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; import { DomSanitizer } from '@angular/platform-browser'; @@ -76,6 +77,7 @@ export class DynamicWidgetComponent extends PageComponent implements IDynamicWid this.ctx.entityService = $injector.get(EntityService); this.ctx.dialogs = $injector.get(DialogService); this.ctx.customDialog = $injector.get(CustomDialogService); + this.ctx.resourceService = $injector.get(ResourceService); this.ctx.date = $injector.get(DatePipe); this.ctx.translate = $injector.get(TranslateService); this.ctx.http = $injector.get(HttpClient); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts index 0ec92e474c..e550148df1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/canvas-digital-gauge.ts @@ -47,7 +47,6 @@ export interface CanvasDigitalGaugeOptions extends GenericOptions { gaugeColor?: string; levelColors?: levelColors; symbol?: string; - label?: string; hideValue?: boolean; hideMinMax?: boolean; fontTitle?: string; @@ -86,6 +85,9 @@ export interface CanvasDigitalGaugeOptions extends GenericOptions { colorTicks?: string; tickWidth?: number; + labelTimestamp?: string + unitTitle?: string; + showUnitTitle?: boolean; showTimestamp?: boolean; } @@ -100,7 +102,6 @@ const defaultDigitalGaugeOptions: CanvasDigitalGaugeOptions = { ...GenericOption levelColors: ['blue'], symbol: '', - label: '', hideValue: false, hideMinMax: false, @@ -145,6 +146,7 @@ interface DigitalGaugeCanvasRenderingContext2D extends CanvasRenderingContext2D } interface BarDimensions { + timeseriesLabelY?: number; baseX: number; baseY: number; width: number; @@ -362,7 +364,7 @@ export class CanvasDigitalGauge extends BaseGauge { const options = this.options as CanvasDigitalGaugeOptions; const elementClone = canvas.elementClone as HTMLCanvasElementClone; if (!elementClone.initialized) { - const context = canvas.contextClone; + const context: DigitalGaugeCanvasRenderingContext2D = canvas.contextClone; // clear the cache context.clearRect(x, y, w, h); @@ -378,8 +380,8 @@ export class CanvasDigitalGauge extends BaseGauge { drawDigitalTitle(context, options); - if (!options.showTimestamp) { - drawDigitalLabel(context, options); + if (options.showUnitTitle) { + drawDigitalLabel(context, options, options.unitTitle, 'labelY'); } drawDigitalMinMax(context, options); @@ -406,7 +408,7 @@ export class CanvasDigitalGauge extends BaseGauge { drawDigitalValue(context, options, this.elementValueClone.renderedValue); if (options.showTimestamp) { - drawDigitalLabel(context, options); + drawDigitalLabel(context, options, options.labelTimestamp, 'timeseriesLabelY'); this.elementValueClone.renderedTimestamp = this.timestamp; } @@ -564,11 +566,12 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, if (options.gaugeType === 'donut') { bd.fontValueBaseline = 'middle'; - if (options.label && options.label.length > 0) { + if (options.showUnitTitle || options.showTimestamp) { const valueHeight = determineFontHeight(options, 'Value', bd.fontSizeFactor).height; const labelHeight = determineFontHeight(options, 'Label', bd.fontSizeFactor).height; const total = valueHeight + labelHeight; bd.labelY = bd.Cy + total / 2; + bd.timeseriesLabelY = determineTimeseriesLabelY(options, bd.labelY, bd.fontSizeFactor) bd.valueY = bd.Cy - total / 2 + valueHeight / 2; } else { bd.valueY = bd.Cy; @@ -577,6 +580,7 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, bd.titleY = bd.Cy - bd.Ro - 12 * bd.fontSizeFactor; bd.valueY = bd.Cy; bd.labelY = bd.Cy + (8 + options.fontLabelSize) * bd.fontSizeFactor; + bd.timeseriesLabelY = determineTimeseriesLabelY(options, bd.labelY, bd.fontSizeFactor) bd.minY = bd.maxY = bd.labelY; if (options.roundedLineCap) { bd.minY += bd.strokeWidth / 2; @@ -595,8 +599,9 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, bd.barTop = bd.valueY + 8 * bd.fontSizeFactor; bd.barBottom = bd.barTop + bd.strokeWidth; - if (options.hideMinMax && options.label === '') { + if (options.hideMinMax && !options.showUnitTitle && !options.showTimestamp) { bd.labelY = bd.barBottom; + bd.timeseriesLabelY = determineTimeseriesLabelY(options, bd.labelY, bd.fontSizeFactor) bd.barLeft = bd.origBaseX + options.fontMinMaxSize / 3 * bd.fontSizeFactor; bd.barRight = bd.origBaseX + w + /*bd.width*/ -options.fontMinMaxSize / 3 * bd.fontSizeFactor; } else { @@ -609,6 +614,7 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, bd.barLeft = bd.minX; bd.barRight = bd.maxX; bd.labelY = bd.barBottom + (8 + options.fontLabelSize) * bd.fontSizeFactor; + bd.timeseriesLabelY = determineTimeseriesLabelY(options, bd.labelY, bd.fontSizeFactor) bd.minY = bd.maxY = bd.labelY; } } else if (options.gaugeType === 'verticalBar') { @@ -618,14 +624,14 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, bd.valueY = bd.titleBottom + (options.hideValue ? 0 : options.fontValueSize * bd.fontSizeFactor); bd.barTop = bd.valueY + 8 * bd.fontSizeFactor; - bd.labelY = bd.baseY + bd.height - 16; - if (options.label === '') { - bd.barBottom = bd.labelY; + bd.labelY = bd.baseY + bd.height; + bd.timeseriesLabelY = determineTimeseriesLabelY(options, bd.labelY, bd.fontSizeFactor) + if (options.showUnitTitle || options.showTimestamp) { + bd.barBottom = bd.labelY - options.fontLabelSize * bd.fontSizeFactor; } else { - bd.barBottom = bd.labelY - (8 + options.fontLabelSize) * bd.fontSizeFactor; + bd.barBottom = bd.labelY } - bd.minX = bd.maxX = - bd.baseX + bd.width / 2 + bd.strokeWidth / 2 + options.fontMinMaxSize / 3 * bd.fontSizeFactor; + bd.minX = bd.maxX = bd.baseX + bd.width / 2 + bd.strokeWidth / 2 + options.fontMinMaxSize / 3 * bd.fontSizeFactor; bd.minY = bd.barBottom; bd.maxY = bd.barTop; bd.fontMinMaxBaseline = 'middle'; @@ -657,6 +663,14 @@ function barDimensions(context: DigitalGaugeCanvasRenderingContext2D, return bd; } +function determineTimeseriesLabelY(options: CanvasDigitalGaugeOptions, labelY: number, fontSizeFactor: number){ + if (options.showUnitTitle) { + return labelY + options.fontLabelSize * fontSizeFactor * 1.2; + } else { + return labelY; + } +} + function determineFontHeight(options: CanvasDigitalGaugeOptions, target: string, baseSize: number): FontHeightInfo { const fontStyleStr = 'font-style:' + options['font' + target + 'Style'] + ';font-weight:' + options['font' + target + 'Weight'] + ';font-size:' + @@ -751,22 +765,22 @@ function drawDigitalTitle(context: DigitalGaugeCanvasRenderingContext2D, options context.restore(); } -function drawDigitalLabel(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions) { - if (!options.label || options.label === '') { +function drawDigitalLabel(context: DigitalGaugeCanvasRenderingContext2D, options: CanvasDigitalGaugeOptions, text: string, nameTextY: string) { + if (!text || text === '') { return; } - const {labelY, baseX, width, fontSizeFactor} = + const {baseX, width, fontSizeFactor} = context.barDimensions; const textX = Math.round(baseX + width / 2); - const textY = labelY; + const textY = context.barDimensions[nameTextY]; context.save(); context.textAlign = 'center'; context.font = Drawings.font(options, 'Label', fontSizeFactor); context.lineWidth = 0; - drawText(context, options, 'Label', options.label, textX, textY); + drawText(context, options, 'Label', text, textX, textY); context.restore(); } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator-panel.component.scss b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator-panel.component.scss index 036398d48e..9ed640d33d 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator-panel.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/date-range-navigator/date-range-navigator-panel.component.scss @@ -29,7 +29,6 @@ .mat-padding { padding: 16px; - min-width: 560px; } - + } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts index 16d536f94d..f640170908 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/digital-gauge.ts @@ -65,6 +65,7 @@ export class TbCanvasDigitalGauge { (settings.unitTitle && settings.unitTitle.length > 0 ? settings.unitTitle : dataKey.label) : ''); + this.localSettings.showUnitTitle = settings.showUnitTitle === true; this.localSettings.showTimestamp = settings.showTimestamp === true; this.localSettings.timestampFormat = settings.timestampFormat && settings.timestampFormat.length ? settings.timestampFormat : 'yyyy-MM-dd HH:mm:ss'; @@ -181,7 +182,8 @@ export class TbCanvasDigitalGauge { roundedLineCap: this.localSettings.roundedLineCap, symbol: this.localSettings.units, - label: this.localSettings.unitTitle, + unitTitle: this.localSettings.unitTitle, + showUnitTitle: this.localSettings.showUnitTitle, showTimestamp: this.localSettings.showTimestamp, hideValue: this.localSettings.hideValue, hideMinMax: this.localSettings.hideMinMax, @@ -400,7 +402,7 @@ export class TbCanvasDigitalGauge { if (this.localSettings.showTimestamp) { timestamp = tvPair[0]; const filter = this.ctx.$injector.get(DatePipe); - (this.gauge.options as CanvasDigitalGaugeOptions).label = + (this.gauge.options as CanvasDigitalGaugeOptions).labelTimestamp = filter.transform(timestamp, this.localSettings.timestampFormat); } const value = tvPair[1]; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts index 979d60bb5b..3c93d03e84 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/flot-widget.ts @@ -312,6 +312,9 @@ export class TbFlot { if (this.settings.stroke) { this.options.series.pie.stroke.color = this.settings.stroke.color || '#fff'; this.options.series.pie.stroke.width = this.settings.stroke.width || 0; + if (this.options.series.pie.stroke.width) { + this.scalingPieRadius(); + } } if (this.options.series.pie.label.show) { @@ -690,22 +693,34 @@ export class TbFlot { } } + private scalingPieRadius() { + let scalingLine; + this.ctx.width > this.ctx.height ? scalingLine = this.ctx.height : scalingLine = this.ctx.width; + let changeRadius = this.options.series.pie.stroke.width / scalingLine; + this.options.series.pie.radius = changeRadius < 1 ? this.settings.radius - changeRadius : 0; + } + public resize() { if (this.resizeTimeoutHandle) { clearTimeout(this.resizeTimeoutHandle); this.resizeTimeoutHandle = null; } if (this.plot && this.plotInited) { - const width = this.$element.width(); - const height = this.$element.height(); - if (width && height) { - this.plot.resize(); - if (this.chartType !== 'pie') { - this.plot.setupGrid(); - } - this.plot.draw(); + if (this.chartType === 'pie' && this.settings.stroke?.width) { + this.scalingPieRadius(); + this.redrawPlot(); } else { - this.resizeTimeoutHandle = setTimeout(this.resize.bind(this), 30); + const width = this.$element.width(); + const height = this.$element.height(); + if (width && height) { + this.plot.resize(); + if (this.chartType !== 'pie') { + this.plot.setupGrid(); + } + this.plot.draw(); + } else { + this.resizeTimeoutHandle = setTimeout(this.resize.bind(this), 30); + } } } } diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts index d72c2798f4..783ebd2096 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/providers/image-map.ts @@ -222,6 +222,7 @@ export class ImageMap extends LeafletMap { maxZoom, scrollWheelZoom: !this.options.disableScrollZooming, center, + doubleClickZoom: !this.options.disableZoomControl, zoomControl: !this.options.disableZoomControl, zoom: 1, crs: L.CRS.Simple, diff --git a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts index 7320b2aeac..f0ba0a93d0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/trip-animation/trip-animation.component.ts @@ -112,14 +112,12 @@ export class TripAnimationComponent implements OnInit, AfterViewInit, OnDestroy item => this.clearIncorrectFirsLastDatapoint(item)).filter(arr => arr.length); this.interpolatedTimeData.length = 0; this.formattedInterpolatedTimeData.length = 0; - if (this.historicalData.length) { - const prevMinTime = this.minTime; - const prevMaxTime = this.maxTime; - this.calculateIntervals(); - const currentTime = this.calculateCurrentTime(prevMinTime, prevMaxTime); - if (currentTime !== this.currentTime) { - this.timeUpdated(currentTime); - } + const prevMinTime = this.minTime; + const prevMaxTime = this.maxTime; + this.calculateIntervals(); + const currentTime = this.calculateCurrentTime(prevMinTime, prevMaxTime); + if (currentTime !== this.currentTime) { + this.timeUpdated(currentTime); } this.mapWidget.map.map?.invalidateSize(); this.mapWidget.map.setLoading(false); diff --git a/ui-ngx/src/app/modules/home/models/services.map.ts b/ui-ngx/src/app/modules/home/models/services.map.ts index 9795dcdeda..f3bd6710f6 100644 --- a/ui-ngx/src/app/modules/home/models/services.map.ts +++ b/ui-ngx/src/app/modules/home/models/services.map.ts @@ -36,6 +36,7 @@ import { BroadcastService } from '@core/services/broadcast.service'; import { ImportExportService } from '@home/components/import-export/import-export.service'; import { DeviceProfileService } from '@core/http/device-profile.service'; import { OtaPackageService } from '@core/http/ota-package.service'; +import { ResourceService } from '@core/http/resource.service'; import { TwoFactorAuthenticationService } from '@core/http/two-factor-authentication.service'; export const ServicesMap = new Map>( @@ -61,6 +62,7 @@ export const ServicesMap = new Map>( ['importExport', ImportExportService], ['deviceProfileService', DeviceProfileService], ['otaPackageService', OtaPackageService], + ['resourceService', ResourceService], ['twoFactorAuthenticationService', TwoFactorAuthenticationService] ] ); diff --git a/ui-ngx/src/app/modules/home/models/widget-component.models.ts b/ui-ngx/src/app/modules/home/models/widget-component.models.ts index fd163df87a..465cade9f2 100644 --- a/ui-ngx/src/app/modules/home/models/widget-component.models.ts +++ b/ui-ngx/src/app/modules/home/models/widget-component.models.ts @@ -72,6 +72,7 @@ import { EntityRelationService } from '@core/http/entity-relation.service'; import { EntityService } from '@core/http/entity.service'; import { DialogService } from '@core/services/dialog.service'; import { CustomDialogService } from '@home/components/widget/dialog/custom-dialog.service'; +import { ResourceService } from '@core/http/resource.service'; import { DatePipe } from '@angular/common'; import { TranslateService } from '@ngx-translate/core'; import { PageLink } from '@shared/models/page/page-link'; @@ -167,6 +168,7 @@ export class WidgetContext { entityService: EntityService; dialogs: DialogService; customDialog: CustomDialogService; + resourceService: ResourceService; date: DatePipe; translate: TranslateService; http: HttpClient; diff --git a/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts index 5af2735a49..24f33a8a03 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts +++ b/ui-ngx/src/app/modules/home/pages/admin/queue/queues-table-config.resolver.ts @@ -17,7 +17,12 @@ import { Injectable } from '@angular/core'; import { ActivatedRouteSnapshot, Resolve, Router } from '@angular/router'; import { EntityTableColumn, EntityTableConfig } from '@home/models/entity/entities-table-config.models'; -import { QueueInfo, ServiceType } from '@shared/models/queue.models'; +import { + QueueInfo, + QueueProcessingStrategyTypesMap, + QueueSubmitStrategyTypesMap, + ServiceType +} from '@shared/models/queue.models'; import { select, Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { BroadcastService } from '@core/services/broadcast.service'; @@ -83,14 +88,14 @@ export class QueuesTableConfigResolver implements Resolve('partitions', 'admin.queue-partitions', '25%'), new EntityTableColumn('submitStrategy', 'admin.queue-submit-strategy', '25%', (entity: QueueInfo) => { - return entity.submitStrategy.type; + return this.translate.instant(QueueSubmitStrategyTypesMap.get(entity.submitStrategy.type).label); }, () => ({}), false ), new EntityTableColumn('processingStrategy', 'admin.queue-processing-strategy', '25%', (entity: QueueInfo) => { - return entity.processingStrategy.type; + return this.translate.instant(QueueProcessingStrategyTypesMap.get(entity.processingStrategy.type).label); }, () => ({}), false diff --git a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts index 67b307662c..843616cce0 100644 --- a/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts +++ b/ui-ngx/src/app/modules/home/pages/rulechain/rulechain-page.component.ts @@ -89,6 +89,10 @@ export class RuleChainPageComponent extends PageComponent return this.isDirtyValue || this.isImport; } + set isDirty(value: boolean) { + this.isDirtyValue = value; + } + @HostBinding('style.width') width = '100%'; @HostBinding('style.height') height = '100%'; diff --git a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts index ff8d2adead..7ef523e7d0 100644 --- a/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts +++ b/ui-ngx/src/app/shared/components/directives/tb-json-to-string.directive.ts @@ -26,6 +26,7 @@ import { Validator } from '@angular/forms'; import { ErrorStateMatcher } from '@angular/material/core'; +import { isObject } from "@core/utils"; @Directive({ selector: '[tb-json-to-string]', @@ -53,7 +54,11 @@ export class TbJsonToStringDirective implements ControlValueAccessor, Validator, @HostListener('input', ['$event.target.value']) input(newValue: any): void { try { this.data = JSON.parse(newValue); - this.parseError = false; + if (isObject(this.data)) { + this.parseError = false; + } else { + this.parseError = true; + } } catch (e) { this.parseError = true; } diff --git a/ui-ngx/src/app/shared/components/json-object-edit.component.ts b/ui-ngx/src/app/shared/components/json-object-edit.component.ts index e7a1b97cad..919dbace34 100644 --- a/ui-ngx/src/app/shared/components/json-object-edit.component.ts +++ b/ui-ngx/src/app/shared/components/json-object-edit.component.ts @@ -22,7 +22,7 @@ import { ActionNotificationHide, ActionNotificationShow } from '@core/notificati import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { CancelAnimationFrame, RafService } from '@core/services/raf.service'; -import { guid, isDefinedAndNotNull, isLiteralObject, isUndefined } from '@core/utils'; +import { guid, isDefinedAndNotNull, isObject, isUndefined } from '@core/utils'; import { ResizeObserver } from '@juggle/resize-observer'; import { getAce } from '@shared/models/ace/ace.models'; @@ -259,7 +259,7 @@ export class JsonObjectEditComponent implements OnInit, ControlValueAccessor, Va if (this.contentValue && this.contentValue.length > 0) { try { data = JSON.parse(this.contentValue); - if (!isLiteralObject(data)) { + if (!isObject(data)) { throw new TypeError(`Value is not a valid JSON`); } this.objectValid = true; diff --git a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts index 25c5b5dc7d..bcad0a000c 100644 --- a/ui-ngx/src/app/shared/models/ace/service-completion.models.ts +++ b/ui-ngx/src/app/shared/models/ace/service-completion.models.ts @@ -100,6 +100,8 @@ export const importEntitiesResultInfoHref = 'CustomDialogComponent'; +export const resourceInfoHref = 'Resource info'; + export const pageLinkArg: FunctionArg = { name: 'pageLink', type: 'PageLink', @@ -1300,6 +1302,23 @@ export const serviceCompletions: TbEditorCompletions = { }, } }, + resourceService: { + description: 'Resource Service API
' + + 'See ResourceService for API reference.', + meta: 'service', + type: 'ResourceService', + children: { + getResources: { + description: 'Find resources by search text', + meta: 'function', + args: [ + pageLinkArg, + requestConfigArg + ], + return: observablePageDataReturnType(resourceInfoHref) + }, + } + }, dialogs: { description: 'Dialogs Service API
' + 'See DialogService for API reference.', diff --git a/ui-ngx/src/app/shared/models/constants.ts b/ui-ngx/src/app/shared/models/constants.ts index 2a01a7eae4..37027edc68 100644 --- a/ui-ngx/src/app/shared/models/constants.ts +++ b/ui-ngx/src/app/shared/models/constants.ts @@ -202,7 +202,7 @@ export const valueTypesMap = new Map( ValueType.JSON, { name: 'value.json', - icon: 'mdi:json' + icon: 'mdi:code-json' } ] ] diff --git a/ui-ngx/src/app/shared/models/queue.models.ts b/ui-ngx/src/app/shared/models/queue.models.ts index dc90781d30..5814a6eeb9 100644 --- a/ui-ngx/src/app/shared/models/queue.models.ts +++ b/ui-ngx/src/app/shared/models/queue.models.ts @@ -75,7 +75,7 @@ export const QueueProcessingStrategyTypesMap = new Mapv1/devices/me/attributes/response/$request_id, v1/devices/me/attributes, v1/devices/me/rpc/request/$request_id, v1/devices/me/rpc/response/$request_id. This setting does not impact attribute and rpc subscriptions sent using new (v2) topics: v2/a/res/$request_id, v2/a, v2/r/req/$request_id, v2/r/res/$request_id. Where $request_id is an integer request identifier.", + "mqtt-send-ack-on-validation-exception": "Enviar PUBACK en error de validación al publicar (PUBLISH)", + "mqtt-send-ack-on-validation-exception-hint": "By default, the platform will close the MQTT session on message validation failure. When enabled, the platform will send publish acknowledgment instead of closing the session.", + "snmp-add-mapping": "Añadir mapeado SNMP", + "snmp-mapping-not-configured": "No hay mapeado OID a series de tiempo/telemetría configurado", + "snmp-timseries-or-attribute-name": "Nombre Series de tiempo/nombre atributo para mapeado", + "snmp-timseries-or-attribute-type": "Tipo Series de tiempo/nombre atributo para mapeado", + "snmp-method-pdu-type-get-request": "GetRequest", + "snmp-method-pdu-type-get-next-request": "GetNextRequest", + "snmp-oid": "OID", + "transport-device-payload-type-json": "JSON", + "transport-device-payload-type-proto": "Protobuf", "mqtt-payload-type-required": "Se requiere tipo de Payload.", + "coap-device-type": "Tipo de dispositivo CoAP", + "coap-device-payload-type": "Payload dispositivo CoAP", + "coap-device-type-required": "Se requiere tipo de dispositivo CoAP.", + "coap-device-type-default": "Por defecto", + "coap-device-type-efento": "Efento NB-IoT", "support-level-wildcards": "Se soportan los wilcards únicos [+] y multi-nivel [#].", "telemetry-topic-filter": "Filtro de topic en telemetría", "telemetry-topic-filter-required": "Se requiere filtro de topic (telemetría).", "attributes-topic-filter": "Filtro de topic en atributos", "attributes-topic-filter-required": "Se requiere filtro de topic (atributos).", - "telemetry-proto-schema": "Proto schema de telemetría", - "telemetry-proto-schema-required": "Se requiere proto schema de telemetría.", - "attributes-proto-schema": "Proto schema de atributos", - "attributes-proto-schema-required": "Se requiere proto schema de atributos.", + "telemetry-proto-schema": "Proto esquema de telemetría", + "telemetry-proto-schema-required": "Se requiere proto esquema de telemetría.", + "attributes-proto-schema": "Proto esquema de atributos", + "attributes-proto-schema-required": "Se requiere proto esquema de atributos.", + "rpc-response-proto-schema": "Proto esquema de respuesta RPC", + "rpc-response-proto-schema-required": "Se requiere proto esquema de respuesta RPC.", "rpc-response-topic-filter": "Filtro de topic de respuesta RPC", - "rpc-response-topic-filter-required": "Se requiere fitro de respuesta RPC.", + "rpc-response-topic-filter-required": "Se requiere filtro de topic respuesta RPC.", + "rpc-request-proto-schema": "Proto esquema de petición RPC", + "rpc-request-proto-schema-required": "Se requiere proto esquema de petición RPC.", + "rpc-request-proto-schema-hint": "Las peticiones RPC deben contener siempre los siguientes campos: string method = 1; int32 requestId = 2; y params = 3 para cualquier tipo de datoas.", "not-valid-pattern-topic-filter": "No es un patrón de filtro válido", "not-valid-single-character": "Uso inválido de wildcard único", "not-valid-multi-character": "Uso inválido de wildcard multi-nivel", @@ -1027,6 +1296,7 @@ "alarm-type": "Tipo de alarma", "alarm-type-required": "Se requiere tipo de alarma.", "alarm-type-unique": "El tipo de alarma, debe ser único dentro de las reglas de alarma del perfil de dispositivo.", + "alarm-type-max-length": "El tipo de alarma debe ser menor de 256", "create-alarm-pattern": "Crear alarma {{alarmType}}", "create-alarm-rules": "Crear reglas de alarma", "no-create-alarm-rules": "No hay condiciones de creación de alarma configuradas", @@ -1046,14 +1316,20 @@ "condition-duration-time-unit-required": "Se requiere una unidad de tiempo.", "advanced-settings": "Ajustes avanzados", "alarm-rule-details": "Detalles", + "alarm-rule-details-hint": "Ayuda: usa ${nombredeClave} para sustituir los valores de atributos o telemetrías usadas en la condición de la regla de alarma.", "add-alarm-rule-details": "Añadir detalles", + "alarm-rule-mobile-dashboard": "Panel Móvil", + "alarm-rule-mobile-dashboard-hint": "Usado por la aplicación móvil como panel de detalle de alarmas", + "alarm-rule-no-mobile-dashboard": "No hay panel seleccionado", "propagate-alarm": "Propagar alarma", "alarm-rule-relation-types-list": "Tipos de relación para propagar", "alarm-rule-relation-types-list-hint": "Si no está seleccionado 'propagar relaciones', las alarmas serán propagadas sin filtrar por relación.", + "propagate-alarm-to-owner": "Propagar alarma al propietario de la entidad (Cliente o Administrador)", + "propagate-alarm-to-tenant": "Propagar alarma a Administrador", "alarm-details": "Detalles de alarma", "alarm-rule-condition": "Condiciones de regla de alarma", "enter-alarm-rule-condition-prompt": "Por favor, añade una condición de alarma", - "edit-alarm-rule-condition": "Editar condición de alarma", + "edit-alarm-rule-condition": "Editar condición de alarma", "device-provisioning": "Aprovisionamiento de dispositivos", "provision-strategy": "Estrategia de aprovisionamiento", "provision-strategy-required": "Se requiere estrategia de aprovisionamiento.", @@ -1073,6 +1349,7 @@ "condition-type-simple": "Simple", "condition-type-duration": "Duración", "condition-during": "Durante {{during}}", + "condition-during-dynamic": "Durante \"{{ attribute }}\" ({{during}})", "condition-type-repeating": "Repetitiva", "condition-type-required": "Se requiere tipo de condición.", "condition-repeating-value": "Nº de eventos", @@ -1080,12 +1357,13 @@ "condition-repeating-value-pattern": "Nº de eventos debe ser un número entero.", "condition-repeating-value-required": "Se requiere Nº de eventos.", "condition-repeat-times": "Repetición { count, plural, 1 {1 vez} other {# veces} }", + "condition-repeat-times-dynamic": "Repetición \"{ atributo }\" ({ count, plural, 1 {1 vez} other {# veces} })", "schedule-type": "Tipo de horario", "schedule-type-required": "Tipo de horario requerido.", "schedule": "Horario", "edit-schedule": "Editar horario de alarma", "schedule-any-time": "Siempre activo", - "schedule-specific-time": "Activo en una hora específica", + "schedule-specific-time": "Activo en una hora específica", "schedule-custom": "Personalizado", "schedule-day": { "monday": "Lunes", @@ -1098,9 +1376,205 @@ }, "schedule-days": "Días", "schedule-time": "Hora", - "schedule-time-from": "De", + "schedule-time-from": "Desde", "schedule-time-to": "Hasta", - "schedule-days-of-week-required": "Debe ser seleccionado por lo menos un día de la semana." + "schedule-days-of-week-required": "Seleccionar por lo menos un día de la semana.", + "create-device-profile": "Crear un nuevo perfil de dispositivo", + "import": "Importar perfil de dispositivo", + "export": "Exportar perfil de dispositivo", + "export-failed-error": "No ha sido posible exportar el perfil de dispositivo: {{error}}", + "device-profile-file": "Archivo de perfil de dispositivo", + "invalid-device-profile-file-error": "No ha sido posible importar perfil de dispositivo: Estructura de datos inválida.", + "power-saving-mode": "Modo de ahorro de energía (PSM)", + "power-saving-mode-type": { + "default": "Usar el del perfil del dispositivo", + "psm": "Power Saving Mode (PSM)", + "drx": "Discontinuous Reception (DRX)", + "edrx": "Extended Discontinuous Reception (eDRX)" + }, + "edrx-cycle": "Ciclo eDRX", + "edrx-cycle-required": "Se requiere ciclo eDRX.", + "edrx-cycle-pattern": "El ciclo eDRX debe ser un número entero positivo.", + "edrx-cycle-min": "El mínimo de ciclo eDRX es de {{ min }} segundos.", + "paging-transmission-window": "Ventana de transmisión (Paging Transmission Window)", + "paging-transmission-window-required": "Se requiere ventana de transmisión (Paging transmission window).", + "paging-transmission-window-pattern": "Ventana de transmision debe ser un número entero positivo.", + "paging-transmission-window-min": "El mínimo de ventana de transmisión es de {{ min }} segundos.", + "psm-activity-timer": "Tiempo Actividad PSM (PSM Activity Timer)", + "psm-activity-timer-required": "Se requiere el tiempo de actividad PSM.", + "psm-activity-timer-pattern": "Tiempo de actividad PSM debe ser un número entero positivo.", + "psm-activity-timer-min": "El tiempo de actividad PSM mínimo es de {{ min }} segundos.", + "lwm2m": { + "object-list": "Lista de objetos", + "object-list-empty": "No hay objetos seleccionados.", + "no-objects-found": "No se encontraron objetos.", + "no-objects-matching": "No hay objetos que coincidan con '{{object}}'.", + "model-tab": "Modelo LWM2M", + "add-new-instances": "Añadir nueva instancia", + "instances-list": "Lista de Instancias", + "instances-list-required": "Se requiere lista de instancias.", + "instance-id-pattern": "El id de instancia debe ser un número entero positivo.", + "instance-id-max": "El id máximo de instancia es {{max}}.", + "instance": "Instancia", + "resource-label": "#ID Nombre Recurso", + "observe-label": "Observar", + "attribute-label": "Atributo", + "telemetry-label": "Telemetría", + "edit-observe-select": "Para editar observar, selecciona telemetría o atributo", + "edit-attributes-select": "Para editar atributo, selecciona telemetría o atributo", + "no-attributes-set": "No hay atributos ajustados", + "key-name": "Nombre de clave", + "key-name-required": "Se requiere nombre de clave", + "attribute-name": "Nombre Atributo", + "attribute-name-required": "Se requiere nombre de atributo.", + "attribute-value": "Valor de atributo", + "attribute-value-required": "Se requiere valor de atributo.", + "attribute-value-pattern": "El valor del atributo debe ser un número entero positivo.", + "edit-attributes": "Edita atributos: {{ name }}", + "view-attributes": "Ver atributos: {{ name }}", + "add-attribute": "Añadir atributo", + "edit-attribute": "Editar atributo", + "view-attribute": "Ver atributos", + "remove-attribute": "Borrar atributos", + "delete-server-text": "Atención, tras la confirmación la configuración del servidor se borrará y será irrecuperable.", + "delete-server-title": "Estas seguro de borrar el servidor?", + "mode": "Configuración de seguridad", + "bootstrap-tab": "Bootstrap", + "bootstrap-server-legend": "Servidor Bootstrap (ShortId...)", + "lwm2m-server-legend": "Servidor LwM2M (ShortId...)", + "server": "Servidor", + "short-id": "Short server ID", + "short-id-tooltip": "Id corto del servidor. Usado como enlace para asociar las instancias de objetos del servidor.\nEste identificador sirve para identificar únicamente cada servidor LwM2M configurado para el cliente LwM2M.\nLos recursos DEBEN ser ajustados cuando el servidor Bootstrap tenga un valor de 'false'.\nLos valores ID:0 and ID:65535 NO DEBEN ser usados para identificar al servidor LwM2M.", + "short-id-required": "Se requiere Short server ID.", + "short-id-range": "Short server ID debe estar en un rango de 1 a 65534.", + "short-id-pattern": "Short server ID debe ser un número entero positivo.", + "lifetime": "Ciclo de vida registro de cliente (Registration Lifetime)", + "lifetime-required": "Se requiere ciclo de vida.", + "lifetime-pattern": "Ciclo de vida debe ser un número entero positivo.", + "default-min-period": "Periodo mínimo entre notificaciones (s)", + "default-min-period-tooltip": "Valor predeterminado que el cliente LwM2M debe usar para el período mínimo de una Observación en ausencia de éste parámetro incluido en una observación.", + "default-min-period-required": "Período mímino requerido.", + "default-min-period-pattern": "El período mínimo debe ser un número entero positivo.", + "notification-storing": "Grabado de notificaciones cuando esté desactivado u offline", + "binding": "Binding", + "binding-type": { + "u": "U: El cliente es alcanzable por UDP en cualquier momento.", + "m": "M: El cliente es alcanzable por MQTT en cualquier momento.", + "h": "H: El cliente es alcanzable por HTTP en cualquier momento.", + "t": "T: El cliente es alcanzable por TCP en cualquier momento.", + "s": "S: El cliente es alcanzable por SMS en cualquier momento.", + "n": "N: El cliente DEBE enviar las respuestas a las peticiones sobre el modo Non-IP (soportado desde la versión LWM2M 1.1).", + "uq": "UQ: Conexión UDP en modo de cola (no soportado desde la versión LWM2M 1.1)", + "uqs": "UQS: Conexiones UDP y SMS activas, UDP en modo cola, SMS en modo estándar (no soportado desde la versión LWM2M 1.1)", + "tq": "TQ: Conexión TCP en modo de cola (no soportado desde la versión LWM2M 1.1)", + "tqs": "TQS: Conexiones TCP y SMS activas, TCP en modo cola, SMS en modo estándar (no soportado desde la versión LWM2M 1.1)", + "sq": "SQ: Conexión SMS en modo de cola (no soportado desde la versión LWM2M 1.1)" + }, + "binding-tooltip": "This is the list in the\"binding\" resource of the LwM2M server object - /1/x/7.\nIndicates the supported binding modes in the LwM2M Client.\nThis value SHOULD be the same as the value in the “Supported Binding and Modes” resource in the Device Object (/3/0/16).\nWhile multiple transports are supported, only one transport binding can be used during the entire Transport Session.\nAs an example, when UDP and SMS are both supported, the LwM2M Client and the LwM2M Server can choose to communicate either over UDP or SMS during the entire Transport Session.", + "bootstrap-server": "Servidor Bootstrap", + "lwm2m-server": "Servidor LwM2M", + "include-bootstrap-server": "Incluir actualizaciónes del servidor Bootstrap", + "bootstrap-update-title": "Ya has configurado un servidor Bootstrap. Estás seguro de que quieres excluir las actualizaciones?", + "bootstrap-update-text": "Atención, tras la confirmación la configuración del servidor Bootstrap será irrecuperable.", + "server-host": "Host", + "server-host-required": "Se requiere Host.", + "server-port": "Puerto", + "server-port-required": "Se requiere Puerto.", + "server-port-pattern": "El puerto debe ser un número entero positivo.", + "server-port-range": "El puerto debe comprender en el rango 1 a 65535.", + "server-public-key": "Clave Pública del Servidor", + "server-public-key-required": "Se requiere la Clave Pública del servidor.", + "client-hold-off-time": "Tiempo de espera (Hold Off Time)", + "client-hold-off-time-required": "Se requiere tiempo de espera.", + "client-hold-off-time-pattern": "El tiempo de espera debe ser un número entero positivo.", + "client-hold-off-time-tooltip": "El tiempo de espera se usa sólamente con un servidor Bootstrap", + "account-after-timeout": "Cuenta tras el tiempo de espera", + "account-after-timeout-required": "Se requiere Cuenta tras el tiempo de espera.", + "account-after-timeout-pattern": "Cuenta tras el tiempo de espera debe ser un número entero positivo.", + "account-after-timeout-tooltip": "Bootstrap-Server Account after the timeout value given by this resource.", + "server-type": "Tipo de servidor", + "add-new-server-title": "Añadir nueva configuración", + "add-server-config": "Añadir configuración de servidor", + "add-lwm2m-server-config": "Añadir Servidor LwM2M", + "no-config-servers": "No hay servidores configurados", + "others-tab": "Otros ajustes", + "client-strategy": "Estrategia del cliente en la conexión", + "client-strategy-label": "Estrategia", + "client-strategy-only-observe": "Realizar un request para observar al cliente tras la conexión inicial", + "client-strategy-read-all": "Leer todos los recursos y realizar un request para observar al cliente tras el registro", + "fw-update": "Actualización de Firmware", + "fw-update-strategy": "Estrategia de actualización de Firmware", + "fw-update-strategy-data": "Enviar actualización de firmware como un fichero binario usando el Objeto 19 y el Recurso 0 (Data)", + "fw-update-strategy-package": "Enviar actualización de firmware como un fichero binario usando el Objeto 5 y el Recurso 0 (Package)", + "fw-update-strategy-package-uri": "Auto-generar una URL CoAP única para la descarga del paquete y enviarla usando el Objeto 5 y el Recurso 1 (Package URI)", + "sw-update": "Actualización de Software", + "sw-update-strategy": "Estrategia de Actualización de Software", + "sw-update-strategy-package": "Enviar como un fichero binario usando el Objeto 9 y el Recurso 2 (Package)", + "sw-update-strategy-package-uri": "Auto-generar una URL CoAP única para la descarga del paquete y enviarla usando el Objeto 9 y el Recurso 3 (Package URI)", + "fw-update-resource": "Recurso CoAP Actualización de Firmware", + "fw-update-resource-required": "Se requiere el Recurso CoAP Actualización de Firmware.", + "sw-update-resource": "Recurso CoAP Actualización de Software", + "sw-update-resource-required": "Se requiere el Recurso CoAP Actualización de Software.", + "config-json-tab": "Configuracion Json Perfil de dispositivo", + "attributes-name": { + "min-period": "Período mínimo", + "max-period": "Período máximo", + "greater-than": "Mayor que", + "less-than": "Menor que", + "step": "Paso", + "min-evaluation-period": "Período mínimo de evaluación", + "max-evaluation-period": "Período máximo de evaluación" + }, + "composite-operations-support": "Soporta operaciones Lectura/Escritura/Observación Compuestas" + }, + "snmp": { + "add-communication-config": "Añadir configuración de comunicaciones", + "add-mapping": "Añadir mapeado", + "authentication-passphrase": "Frase de contraseña", + "authentication-passphrase-required": "Se requiere frase de contraseña.", + "authentication-protocol": "Protocolo de autenticación", + "authentication-protocol-required": "Se requiere Protocolo de autenticación.", + "communication-configs": "Configuracion de comunicaciones", + "community": "Community", + "community-required": "Se requiere Community.", + "context-name": "Nombre de contexto", + "data-key": "Clave de datos", + "data-key-required": "Se requiere clave de datos.", + "data-type": "Tipo de datos", + "data-type-required": "Se requiere tipo de datos.", + "engine-id": "Engine ID", + "host": "Host", + "host-required": "Se requiere Host.", + "oid": "OID", + "oid-pattern": "Formato OID inválido.", + "oid-required": "Se requiere OID.", + "please-add-communication-config": "Por favor, añadir configuración de comunicación", + "please-add-mapping-config": "Por favor, añadir configuración de mapeado", + "port": "Puerto", + "port-format": "Formato de puerto inválido.", + "port-required": "Se requiere puerto.", + "privacy-passphrase": "Frase de clave de privacidad", + "privacy-passphrase-required": "Se requiere Frase de clave de privacidad.", + "privacy-protocol": "Protocolo privacidad", + "privacy-protocol-required": "Se requiere Protocolo privacidad.", + "protocol-version": "Versión protocolo", + "protocol-version-required": "Se requiere versión protocolo.", + "querying-frequency": "Frecuencia de peticiones, ms", + "querying-frequency-invalid-format": "Frecuencia de peticiones debe ser un número entero positivo.", + "querying-frequency-required": "Se requiere frecuencia de peticiones.", + "retries": "Reintentos", + "retries-invalid-format": "Reintentos debe ser un número entero positivo.", + "retries-required": "Se requiere reintentos.", + "scope": "Alcance", + "scope-required": "Se requiere alcance.", + "security-name": "Nombre seguridad", + "security-name-required": "Se requiere Nombre seguridad.", + "timeout-ms": "Timeout, ms", + "timeout-ms-invalid-format": "Timeout debe ser un número entero positivo.", + "timeout-ms-required": "Se requiere timeout.", + "user-name": "Usuario", + "user-name-required": "Se requiere usuario." + } }, "dialog": { "close": "Cerrar diálogo" @@ -1113,6 +1587,9 @@ "edge": "Borde", "edge-instances": "Instancias de Borde", "edge-file": "Archivo de borde", + "name-max-length": "El nombre debe ser menor de 256", + "label-max-length": "La etiqueta debe ser menor de 256", + "type-max-length": "El tipo debe ser menor de 256", "management": "Gestión de bordes", "no-edges-matching": "No se encontraron bordes que coincidan con '{{entity}}'", "add": "Agregar borde", @@ -1125,7 +1602,7 @@ "delete-edges-title": "¿Está seguro de que desea edge {count, plural, 1 {1 borde} other {# bordes} }?", "delete-edges-text": "Tenga cuidado, después de la confirmación se eliminarán todos los bordes seleccionados y todos los datos relacionados se volverán irrecuperables", "name": "Nombre", - "name-starts-with": "Edge name starts with", + "name-starts-with": "Nombre de Borde comienza con", "name-required": "Se requiere nombre", "description": "Descripción", "details": "Detalles", @@ -1133,8 +1610,8 @@ "copy-id": "Copiar ID de borde", "id-copied-message": "El ID de borde se ha copiado al portapapeles", "sync": "Sinc Edge", - "edge-required": "Edge required", - "edge-type": "Type de la bordure", + "edge-required": "Borde Requerido", + "edge-type": "Tipo de Borde", "edge-type-required": "El tipo de borde es requerido.", "event-action": "Información de la entidad", "entity-id": "ID de entidad", @@ -1155,7 +1632,7 @@ "make-public-edge-title": "¿Estás seguro de que quieres hacer público el edge '{{edgeName}}'?", "make-public-edge-text": "Después de la confirmación, el borde y todos sus datos serán públicos y accesibles para otros", "make-private": "Hacer que edge sea privado", - "public": "Public", + "public": "Público", "make-private-edge-title": "¿Está seguro de que desea que el borde '{{edgeName}}' sea privado?", "make-private-edge-text": "Después de la confirmación, el borde y todos sus datos se harán privados y otros no podrán acceder a ellos", "import": "Importar borde", @@ -1198,40 +1675,40 @@ "widget-datasource-error": "Este widget solo admite la fuente de datos de la entidad EDGE" }, "edge-event": { - "type-dashboard": "Dashboard", - "type-asset": "Asset", - "type-device": "Device", - "type-device-profile": "Device Profile", - "type-entity-view": "Entity View", - "type-alarm": "Alarm", - "type-rule-chain": "Rule Chain", - "type-rule-chain-metadata": "Rule Chain Metadata", - "type-edge": "Edge", - "type-user": "User", - "type-customer": "Customer", - "type-relation": "Relation", - "type-widgets-bundle": "Widgets Bundle", - "type-widgets-type": "Widgets Type", - "type-admin-settings": "Admin Settings", - "action-type-added": "Added", - "action-type-deleted": "Deleted", - "action-type-updated": "Updated", - "action-type-post-attributes": "Post Attributes", - "action-type-attributes-updated": "Attributes Updated", - "action-type-attributes-deleted": "Attributes Deleted", - "action-type-timeseries-updated": "Timeseries Updated", - "action-type-credentials-updated": "Credentials Updated", - "action-type-assigned-to-customer": "Assigned to Customer", - "action-type-unassigned-from-customer": "Unassigned from Customer", - "action-type-relation-add-or-update": "Relation Add or Update", - "action-type-relation-deleted": "Relation Deleted", - "action-type-rpc-call": "RPC Call", - "action-type-alarm-ack": "Alarm Ack", - "action-type-alarm-clear": "Alarm Clear", - "action-type-assigned-to-edge": "Assigned to Edge", - "action-type-unassigned-from-edge": "Unassigned from Edge", - "action-type-credentials-request": "Credentials Request", - "action-type-entity-merge-request": "Entity Merge Request" + "type-dashboard": "Panel", + "type-asset": "Activo", + "type-device": "Dispositivo", + "type-device-profile": "Perfil de dispositivo", + "type-entity-view": "Vista de entidad", + "type-alarm": "Alarma", + "type-rule-chain": "Cadena de reglas", + "type-rule-chain-metadata": "Metadatos de Cadena de Reglas", + "type-edge": "Borde", + "type-user": "Usuario", + "type-customer": "Cliente", + "type-relation": "Relación", + "type-widgets-bundle": "Paquete de Widgets", + "type-widgets-type": "Tipos de Widgets", + "type-admin-settings": "Ajustes de Administración", + "action-type-added": "Añadido", + "action-type-deleted": "Borrado", + "action-type-updated": "Actualizado", + "action-type-post-attributes": "Envío de Atributos", + "action-type-attributes-updated": "Atributos Actualizados", + "action-type-attributes-deleted": "Atributos Borrados", + "action-type-timeseries-updated": "Series de tiempo Actualizadas", + "action-type-credentials-updated": "Credenciales Actualizadas", + "action-type-assigned-to-customer": "Asignado a Cliente", + "action-type-unassigned-from-customer": "Desasignado de Cliente", + "action-type-relation-add-or-update": "Añadir o Actualizar relación", + "action-type-relation-deleted": "Relación borrada", + "action-type-rpc-call": "Llamada RPC", + "action-type-alarm-ack": "ACK Alarma", + "action-type-alarm-clear": "Borrado de Alarma", + "action-type-assigned-to-edge": "Asignado a Borde", + "action-type-unassigned-from-edge": "Desasignado de Borde", + "action-type-credentials-request": "Obtención de Credenciales", + "action-type-entity-merge-request": "Unión de entidades" }, "error": { "unable-to-connect": "Imposible conectar con el servidor! Por favor, revise su conexión a internet.", @@ -1241,6 +1718,7 @@ "entity": { "entity": "Entidad", "entities": "Entidades", + "entities-count": "Nº de entidades", "aliases": "Alias de entidad", "entity-alias": "Alias de entidad", "unable-delete-entity-alias-title": "No ha sido posible eliminar el alias de entidad", @@ -1261,6 +1739,7 @@ "no-entities-matching": "No se han encontrado entidades que coincidan con '{{entity}}' .", "no-entity-types-matching": "No se han encontrado tipos de entidad que coincidan con '{{entityType}}' .", "name-starts-with": "Nombre empieza con", + "help-text": "Usar el símbolo '%' de acuerdo a las necesidades: '%entity_name_contains%', '%entity_name_ends', 'entity_starts_with'.", "use-entity-name-filter": "Usar filtro", "entity-list-empty": "No hay entidades seleccionadas.", "entity-type-list-empty": "No hay tipos de entidad seleccionados.", @@ -1350,7 +1829,9 @@ "type-edge": "Borde", "type-edges": "Bordes", "list-of-edges": "{count, plural, 1 {Un borde} other {Lista de # bordes} }", - "edge-name-starts-with": "Bordes cuyos nombres comienzan con '{{prefijo}}'" + "edge-name-starts-with": "Bordes cuyos nombres comienzan con '{{prefijo}}'", + "type-tb-resource": "Recurso", + "type-ota-package": "Paquete OTA" }, "entity-field": { "created-time": "Hora de creación", @@ -1392,6 +1873,7 @@ "remove-alias": "Borrar alias de la vista de entidad", "add-alias": "Añadir alias a la vista de entidad", "name-starts-with": "Nombre de vista de entidad comienza con", + "help-text": "Usar el símbolo '%' de acuerdo a las necesidades: '%entity-view_name_contains%', '%entity-view_name_ends', 'entity-view_starts_with'.", "entity-view-list": "Lista de vistas de entidad", "use-entity-view-name-filter": "Usar el filtro", "entity-view-list-empty": "No hay vistas de entidad seleccionadas.", @@ -1402,6 +1884,7 @@ "assign-to-customer": "Asignar a cliente", "assign-entity-view-to-customer": "Asignar vista de entidad a cliente", "assign-entity-view-to-customer-text": "Por favor, seleccione las vistas de entidad para asignar al cliente", + "assign-entity-view-to-edge-title": "Asignar vista(s) de entidad a Borde", "no-entity-views-text": "No se encontraron vistas de entidad", "assign-to-customer-text": "Por favor, seleccione el cliente para asignar la vista de entidad", "entity-view-details": "Detalles de la vista de entidad", @@ -1435,6 +1918,8 @@ "created-time": "Fecha de creación", "name": "Nombre", "name-required": "Nombre Requerido.", + "name-max-length": "Nombre debe ser menor de 256", + "type-max-length": "Tipo de vista de entidad debe ser menor de 256", "description": "Descripción", "events": "Eventos", "details": "Detalles", @@ -1464,12 +1949,12 @@ "attributes-propagation-hint": "La vista de entidad copiará automáticamente los atributos especificados de la entidad de destino cada vez que guarde o actualice esta vista de entidad. Por razones de rendimiento, los atributos de entidad objetivo no se propagan a la vista de entidad en cada cambio de atributo. Puede habilitar la propagación automática configurando el nodo de la regla \"copiar a la vista\" en su cadena de reglas y vincular los mensajes \"Atributos de la publicación\" y \"Atributos actualizados\" al nuevo nodo de la regla.", "timeseries-data": "Datos de series temporales", "timeseries-data-hint": "Configure las claves de los datos de las series temporales de la entidad de destino que serán accesibles para la vista de la entidad. Los datos de esta serie temporal son de solo lectura.", + "search": "Buscar vistas de entidad", + "selected-entity-views": "{ count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } seleccionadas", "make-public-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea pública?", "make-public-entity-view-text": "Tras la confirmación, la vista de la entidad y todos sus datos se harán públicos y accesibles para otros.", "make-private-entity-view-title": "¿Está seguro de que desea que la vista de entidad '{{entityViewName}}' sea privada?", "make-private-entity-view-text": "Tras la confirmación, la vista de la entidad y todos sus datos se harán privados y no serán accesibles para otros.", - "search": "Buscar vistas de entidad", - "selected-entity-views": "{ count, plural, 1 {1 vista de entidad} other {# vistas de entidad} } seleccionadas", "assign-entity-view-to-edge": "Asignar vista (s) de entidad a borde", "assign-entity-view-to-edge-text": "Seleccione las vistas de entidad para asignar al borde", "unassign-entity-view-from-edge-title": "¿Está seguro de que desea anular la asignación de la vista de entidad '{{entityViewName}}'?", @@ -1481,14 +1966,15 @@ }, "event": { "event-type": "Tipo de evento", + "events-filter": "Filtro de Eventos", + "clean-events": "Borrar Eventos", "type-error": "Error", "type-lc-event": "Ciclo de vida del evento", "type-stats": "Estadísticas", "type-debug-rule-node": "Debug", "type-debug-rule-chain": "Debug", "no-events-prompt": "Ningún evento encontrado.", - "error": "Error", - "type-edge-event": "Downlink", + "error": "Error", "alarm": "Alarma", "event-time": "Hora del evento", "server": "Servidor", @@ -1506,9 +1992,17 @@ "success": "Éxito", "failed": "Fallo", "messages-processed": "Mensajes procesados", + "min-messages-processed": "Mínimo de mensajes procesados", "errors-occurred": "Ocurrieron errores", + "min-errors-occurred": "Minimum errors occurred", + "min-value": "El valor mínimo es 0.", "all-events": "Todos", - "entity-type": "Tipo de entidad" + "has-error": "Tiene error", + "entity-id": "Id de Entidad", + "entity-type": "Tipo de entidad", + "clear-filter": "Limpiar Filtro", + "clear-request-title": "Borrar todos los eventos", + "clear-request-text": "Estás seguro de borrar todos los eventos?" }, "extension": { "extensions": "Extensiones", @@ -1668,25 +2162,25 @@ "invalid-file-error": "Fichero de extensiones inválido" }, "filter": { - "add": "Añadir filtro", - "edit": "Editar filtro", - "name": "Nombre de filtro", - "name-required": "Se requiere nombre de filtro.", - "duplicate-filter": "Ya existe un filtro con el mismo nombre.", - "filters": "Filtros", - "unable-delete-filter-title": "Error borrando filtro", - "unable-delete-filter-text": "El filtro '{{filter}}' no puede ser borrado debido a que está siendo usado actualmente por los siguientes widgets:
{{widgetsList}}", - "duplicate-filter-error": "Se ha encontrado un filtro duplicado '{{filter}}'.
Los filtros deben ser únicos en el panel.", - "missing-key-filters-error": "No se encontró la clave de filtros para el filtro '{{filter}}'.", - "filter": "Filtro", - "editable": "Editable", - "no-filters-found": "No se encontraron filtros.", - "no-filter-text": "No se ha especificado filtro", - "add-filter-prompt": "Por favos, añadir filtro", - "no-filter-matching": "'{{filter}}' no encontrado.", - "create-new-filter": "Crear un filtro nuevo!", - "filter-required": "Se requiere filtro.", - "operation": { + "add": "Añadir filtro", + "edit": "Editar filtro", + "name": "Nombre de filtro", + "name-required": "Se requiere nombre de filtro.", + "duplicate-filter": "Ya existe un filtro con el mismo nombre.", + "filters": "Filtros", + "unable-delete-filter-title": "Error borrando filtro", + "unable-delete-filter-text": "El filtro '{{filter}}' no puede ser borrado debido a que está siendo usado actualmente por los siguientes widgets:
{{widgetsList}}", + "duplicate-filter-error": "Se ha encontrado un filtro duplicado '{{filter}}'.
Los filtros deben ser únicos en el panel.", + "missing-key-filters-error": "No se encontró la clave de filtros para el filtro '{{filter}}'.", + "filter": "Filtro", + "editable": "Editable", + "no-filters-found": "No se encontraron filtros.", + "no-filter-text": "No se ha especificado filtro", + "add-filter-prompt": "Por favos, añadir filtro", + "no-filter-matching": "'{{filter}}' no encontrado.", + "create-new-filter": "Crear un filtro nuevo!", + "filter-required": "Se requiere filtro.", + "operation": { "operation": "Operación", "equal": "igual", "not-equal": "no igual", @@ -1699,7 +2193,9 @@ "greater-or-equal": "mayor o igual", "less-or-equal": "menor o igual", "and": "y", - "or": "o" + "or": "o", + "in": "en", + "not-in": "no en" }, "ignore-case": "Ignorar mayús/minus", "value": "Valor", @@ -1725,7 +2221,8 @@ "key-type": "Tipo de clave", "attribute": "Atributo", "timeseries": "Timeseries", - "entity-field": "Campo de entidad" + "entity-field": "Campo de entidad", + "constant": "Constante" }, "value-type": { "value-type": "Tipo de valor", @@ -1752,7 +2249,9 @@ "no-dynamic-value": "Sin valor dinámico", "source-attribute": "Atributo de origen", "switch-to-dynamic-value": "Cambiar a valor dinámico", - "switch-to-default-value": "Cambiar a valor por defecto" + "switch-to-default-value": "Cambiar a valor por defecto", + "inherit-owner": "Heredar de propietario", + "source-attribute-not-set": "Si los atributos de origen no están seleccionados" }, "fullscreen": { "expand": "Expandir a Pantalla Completa", @@ -1851,7 +2350,8 @@ "scroll-to-top": "Ir hacia arriba" }, "help": { - "goto-help-page": "Ir a la página de ayuda" + "goto-help-page": "Ir a la página de ayuda", + "show-help": "Mostrar ayuda" }, "home": { "home": "Principal", @@ -1861,17 +2361,31 @@ "avatar": "Avatar", "open-user-menu": "Abrir menú de usuario" }, + "file-input": { + "browse-file": "Navegar fichero", + "browse-files": "Navegar ficheros" + }, + "image-input": { + "drop-image-or": "Arrastrar y soltar una imagen o", + "drop-images-or": "Arrastrar y soltar imagenes o", + "no-images": "No hay imágenes seleccionadas", + "images": "imágenes" + }, "import": { "no-file": "Ningún archivo seleccionado", "drop-file": "Suelte un archivo JSON o haga clic para seleccionar un archivo para cargar.", + "drop-json-file-or": "Suele un archivo JSON o", "drop-file-csv": "Suelte un archivo CSV o haga clic para seleccionar un archivo para cargar.", + "drop-file-csv-or": "Suelte un archivo CSV o", "column-value": "Valor", "column-title": "Título", "column-example": "Datos de ejemplo", "column-key": "Clave de atributo/telemetría", + "credentials": "Credenciales", "csv-delimiter": "Delimitador CSV", "csv-first-line-header": "La primera línea contiene nombres de columna.", "csv-update-data": "Actualizar atributos/telemetría", + "details": "Detalles", "import-csv-number-columns-error": "Un archivo debe contener al menos dos columnas", "import-csv-invalid-format-error": "Formato de archivo inválido. Línea: '{{line}}'", "column-type": { @@ -1885,9 +2399,30 @@ "timeseries": "Series de tiempo", "entity-field": "Campo de entidad", "access-token": "Token de acceso", + "x509": "X.509", + "mqtt": { + "client-id": "Client ID MQTT", + "user-name": "Usuario MQTT", + "password": "Contraseña MQTT" + }, + "lwm2m": { + "client-endpoint": "Nombre endpoint cliente LwM2M", + "security-config-mode": "Configuración de seguridad LwM2M", + "client-identity": "Identidad cliente LwM2M", + "client-key": "Clave cliente LwM2M", + "client-cert": "Clave pública cliente LwM2M", + "bootstrap-server-security-mode": "Modo seguridad servidor Bootstrap LwM2M", + "bootstrap-server-secret-key": "Clave secreta servidor Bootstrap LwM2M", + "bootstrap-server-public-key-id": "Clave pública o id servidor Bootstrap LwM2M", + "lwm2m-server-security-mode": "Modo seguridad servidor LwM2M", + "lwm2m-server-secret-key": "Clave secreta servidor LwM2M", + "lwm2m-server-public-key-id": "Clave pública servidor LwM2M" + }, "isgateway": "Es Gateway", "activity-time-from-gateway-device": "Fecha de actividad desde el dispositivo gateway", - "description": "Descripción" + "description": "Descripción", + "routing-key": "Clave Edge", + "secret": "Secreto Edge" }, "stepper-text": { "select-file": "Seleccione un archivo", @@ -1896,7 +2431,7 @@ "creat-entities": "Creando nuevas entidades" }, "message": { - "create-entities": "Se crearon{{count}} nuevas entidades correctamente.", + "create-entities": "Se crearon {{count}} nuevas entidades correctamente.", "update-entities": "{{count}} entidades se actualizaron correctamente.", "error-entities": "Se produjo un error al crear {{count}} entidades." } @@ -1940,6 +2475,8 @@ "avg": "promedio", "total": "total", "comparison-time-ago": { + "previousInterval": "(intervalo anterior)", + "customInterval": "(intervalo personalizado)", "days": "(hace un día)", "weeks": "(hace una semana)", "months": "(hace un mes)", @@ -1951,6 +2488,7 @@ "request-password-reset": "Solicitar restablecer contraseña", "reset-password": "Restablecer contraseña", "create-password": "Crear contraseña", + "two-factor-authentication": "Two factor authentication", "passwords-mismatch-error": "¡Las contraseñas introducidas deben ser iguales!", "password-again": "Repita la contraseña de nuevo", "sign-in": "Por favor, inicie sesión", @@ -1963,9 +2501,93 @@ "new-password-again": "Repita la nueva contraseña", "password-link-sent-message": "Se ha enviado el enlace de restablecimiento de contraseña con éxito!", "email": "Email", - "login-with": "Iniciar sesión con {{name}}", + "login-with": "Login con {{name}}", "or": "o", - "error": "Error de login" + "error": "Error de Login", + "verify-your-identity": "Verificar identidad", + "select-way-to-verify": "Selecciona el modo de verificación", + "resend-code": "Reenviar código", + "resend-code-wait": "Reenviar código en { time, plural, 1 {1 segundo} other {# segundos} }", + "try-another-way": "Otros modos de verificación", + "totp-auth-description": "Por favor, introduce el código de seguridad de tu aplicación de autenticación.", + "totp-auth-placeholder": "Código", + "sms-auth-description": "Se ha enviado un código de verificación a tu número: {{contact}} proporcionado.", + "sms-auth-placeholder": "Código SMS", + "email-auth-description": "Se ha enviado un código de verificación al email {{contact}} proporcionado.", + "email-auth-placeholder": "Código Email", + "backup-code-auth-description": "Por favor, introduce el código de backup.", + "backup-code-auth-placeholder": "Código de Backup" + }, + "markdown": { + "edit": "Editar", + "preview": "Previsualizar", + "copy-code": "Click para copiar", + "copied": "Copiado!" + }, + "ota-update": { + "add": "Añadir paquete", + "assign-firmware": "Firmware asignado", + "assign-firmware-required": "Firmware asignado requerido", + "assign-software": "Software asignado", + "assign-software-required": "Software asignado requerido", + "auto-generate-checksum": "Auto-generar checksum", + "checksum": "Checksum", + "checksum-hint": "Si el checksum está vacío, se generará automáticamente", + "checksum-algorithm": "Algoritmo checksum", + "checksum-copied-message": "El checksum del paquete se ha copiado al portapapeles", + "change-firmware": "El cambio del firmware provocará la actualización de { count, plural, 1 {1 dispositivo} other {# dispositivos} }.", + "change-software": "El cambio del software provocará la actualización de { count, plural, 1 {1 dispositivo} other {# dispositivos} }.", + "chose-compatible-device-profile": "El paquete subido, sólamente estará disponible para los dispositivos con el perfil seleccionado.", + "chose-firmware-distributed-device": "Elige el firmware que se distribuirá a los dispositivos", + "chose-software-distributed-device": "Elige el software que se distribuirá a los dispositivos", + "content-type": "Tipo de contenido", + "copy-checksum": "Copiar checksum", + "copy-direct-url": "Copiar URL directa", + "copyId": "Copiar Id de paquete", + "copied": "Copiado!", + "delete": "Borrar paquete", + "delete-ota-update-text": "Atención, tras la confirmación la actualización OTA será irrecuperable.", + "delete-ota-update-title": "Estás seguro de borrar la actualización OTA '{{title}}'?", + "delete-ota-updates-text": "Atención, tras la confirmación todas las actualizaciones OTA seleccionadas se borrarán.", + "delete-ota-updates-title": "Estás seguro de borrar { count, plural, 1 {1 Actualización OTA} other {# Actualizaciones OTA} }?", + "description": "Descripción", + "direct-url": "URL Directa", + "direct-url-copied-message": "La URL directa del paquete se ha copiado al portapapeles", + "direct-url-required": "URL Directa requerida", + "download": "Descargar paquete", + "drop-file": "Arrastra un fichero o haz click para seleccionar un fichero a subir.", + "drop-package-file-or": "Arrastrar y soltar un fichero o", + "file-name": "Nombre del fichero", + "file-size": "Tamaño del fichero", + "file-size-bytes": "Tamaño del fichero en bytes", + "idCopiedMessage": "El Id del paquete se ha copiado al portapapeles", + "no-firmware-matching": "No se ha encontrado ningún paquete de firmware OTA compatible que coincidan con '{{entity}}'.", + "no-firmware-text": "No hay aprovisionado ningún paquete de firmware OTA.", + "no-packages-text": "No se han encontrado paquetes", + "no-software-matching": "No se ha encontrado ningún paquete de software OTA compatible que coincidan con '{{entity}}'.", + "no-software-text": "No hay aprovisionado ningún paquete de software OTA.", + "ota-update": "Actualización OTA", + "ota-update-details": "Detalles de actualización OTA", + "ota-updates": "Actualizaciones OTA", + "package-type": "Tipo de paquete", + "packages-repository": "Repositorio de paquetes", + "search": "Buscar paquetes", + "selected-package": "{ count, plural, 1 {1 paquete} other {# paquetes} } selected", + "title": "Título", + "title-required": "Título requerido.", + "title-max-length": "El título debe ser menor de 256", + "types": { + "firmware": "Firmware", + "software": "Software" + }, + "upload-binary-file": "Subir fichero binario", + "use-external-url": "Usar una URL externa", + "version": "Versión", + "version-required": "Versión requerida.", + "version-tag": "Tag de Versión", + "version-tag-hint": "El tag de versión debe coincidir con la versión reportada por el dispositivo.", + "version-max-length": "Versión debe ser menor que 256", + "warning-after-save-no-edit": "Una vez que el paquete se haya subido, no se podrá modificar el título, versión, perfil de dispositivo y tipo de paquete." }, "position": { "top": "Superior", @@ -1977,7 +2599,68 @@ "profile": "Perfil", "last-login-time": "Último acceso", "change-password": "Cambiar contraseña", - "current-password": "Contraseña actual" + "current-password": "Contraseña actual", + "copy-jwt-token": "Copiar JWT", + "valid-till": "Válido hasta {{expirationData}}", + "tokenCopiedSuccessMessage": "JWT copiado al portapapeles", + "tokenCopiedWarnMessage": "JWT caducado, por favor actualiza la página." + }, + "security": { + "security": "Seguridad", + "2fa": { + "2fa": "Autenticación de doble factor (2FA)", + "2fa-description": "La autenticación de doble factor proteje tu cuenta de accesos no autorizados. Lo único que tienes que hacer es entrar un código de seguridad al hacer login.", + "authenticate-with": "Puedes autenticarte con:", + "disable-2fa-provider-text": "Desactivar {{name}} hará tu cuenta menos segura", + "disable-2fa-provider-title": "Estás seguro de desactivar {{name}}?", + "get-new-code": "Obtener un nuevo código", + "main-2fa-method": "Usar como método de autenticación de doble factor principal", + "dialog": { + "activation-step-description-email": "La próxima vez que hagas log-in, se deberá introducir el código de seguridad que se enviará a tu dirección de email.", + "activation-step-description-sms": "La próxima vez que hagas log-in, se deberá introducir el código de seguridad que se enviará a tu número de teléfono.", + "activation-step-description-totp": "La próxima vez que hagas log-in, se deberá introducir el código de seguridad de doble factor.", + "activation-step-label": "Activación", + "backup-code-description": "Imprime los códigos y guárdalos en un lugar seguro, se necesitarán para hacer login en tu cuenta. Puedes usar cada código de backup sólo una vez.", + "backup-code-warn": "Una vez que salgas de esta página, estos códigos no se volverán a mostrar. Guárdalos en un lugar seguro usando las opciones a continuación.", + "download-txt": "Descargar (txt)", + "email-step-description": "Introduce tu email para usar como autenticador.", + "email-step-label": "Email", + "enable-email-title": "Activar autenticador por email", + "enable-sms-title": "Activar autenticador por SMS", + "enable-totp-title": "Activar autenticador por app", + "enter-verification-code": "Entra el código de 6-dígitos", + "get-backup-code-title": "Obtener copia de seguridad", + "next": "Siguiente", + "scan-qr-code": "Escanea el código QR con tu aplicación de autenticación", + "send-code": "Enviar código", + "sms-step-description": "Introduce tu número de teléfono para usar como autenticador.", + "sms-step-label": "Número de teléfono", + "success": "Éxito!", + "totp-step-description-install": "Puedes instalar la aplicación Google Authenticator, Authy, o Duo.", + "totp-step-description-open": "Abre la aplicación de autenticación en tu teléfono móvil.", + "totp-step-label": "Obtener app", + "verification-code": "Código de 6-dígitos", + "verification-code-invalid": "Formáto de código inválido", + "verification-code-incorrect": "El código de verificación es incorrecto", + "verification-code-many-request": "Demasiadas solicitudes, revisa el código de verificación", + "verification-step-description": "Introduce el código de 6-dígitos que acabamos de enviar a {{address}}", + "verification-step-label": "Verificación" + }, + "provider": { + "email": "Email", + "email-description": "Usar un código de seguridad enviado a tu email para autenticarte.", + "email-hint": "Los códigos de autenticación se han enviado por email a {{ info }}", + "sms": "SMS", + "sms-description": "Usar tu teléfono para autenticarte. Enviaremos un código de seguridad vía SMS.", + "sms-hint": "Los códigos de autenticación se han enviado por mensaje de texto SMS a {{ info }}", + "totp": "App de autenticación", + "totp-description": "Usar aplicaciones como Google Authenticator, Authy, o Duo en tu teléfono para autenticarte. Se generará un código de seguridad para hacer login.", + "totp-hint": "La aplicación de autenticación se ha configurado en tu cuenta", + "backup_code": "Código Backup", + "backup-code-description": "Estos códigos de seguridad imprimibles son de un solo uso, te permiten identificarte cuando no tengas el teléfono a mano, útil cuando se viaja.", + "backup-code-hint": "{{ info }} códigos de un solo uso activos en este momento" + } + } }, "relation": { "relations": "Relaciones", @@ -2003,6 +2686,7 @@ "delete": "Borrar relación", "relation-type": "Tipo de relación", "relation-type-required": "Tipo de relación requerido.", + "relation-type-max-length": "Tipo de relación debe ser menor de 256", "any-relation-type": "Cualquier tipo", "add": "Añadir relación", "edit": "Editar relación", @@ -2022,6 +2706,35 @@ "invalid-additional-info": "Error al analizar el fichero JSON de información adicional.", "no-relations-text": "No se encontraron relaciones" }, + "resource": { + "add": "Añadir Recurso", + "copyId": "Copiar Id de recurso", + "delete": "Borrar recurso", + "delete-resource-text": "Atención, tras la confirmación el recurso será irrecuperable.", + "delete-resource-title": "Estás seguro de borrar el recurso '{{resourceTitle}}'?", + "delete-resources-action-title": "Borrar { count, plural, 1 {1 recurso} other {# recursos} }", + "delete-resources-text": "Los recursos serán borrados, incluso si están siendo usados en los perfiles de dispositivo.", + "delete-resources-title": "Estás seguro de borrar { count, plural, 1 {1 recurso} other {# recursos} }?", + "download": "Descargar recurso", + "drop-file": "Arrastra un fichero o haz click para seleccionar un fichero a subir.", + "drop-resource-file-or": "Arrastrar y soltar un fichero o", + "empty": "El recurso está vacío", + "file-name": "Nombre de fichero", + "idCopiedMessage": "El Id de recurso ha sido copiado al portapapeles", + "no-resource-matching": "No se han encontrado recursos que coincidan con '{{widgetsBundle}}'.", + "no-resource-text": "No se encontraron recursos", + "open-widgets-bundle": "Abrir paquete de widgets", + "resource": "Recurso", + "resource-library-details": "Detalles de recurso", + "resource-type": "Tipo de recurso", + "resources-library": "Librería de recursos", + "search": "Buscar recursos", + "selected-resources": "{ count, plural, 1 {1 recurso} other {# recursos} } seleccionados", + "system": "Sistema", + "title": "Título", + "title-required": "Título requerido.", + "title-max-length": "El título debe ser menor de 256" + }, "rulechain": { "rulechain": "Cadena de Regla", "rulechains": "Cadenas de Reglas", @@ -2029,6 +2742,7 @@ "delete": "Borrar cadena de reglas", "name": "Nombre", "name-required": "Nombre requerido.", + "name-max-length": "Nombre debe ser menor de 256", "description": "Descripción", "add": "Añadir Cadena", "set-root": "Hacer la cadena de reglas Raíz", @@ -2061,14 +2775,12 @@ "search": "Buscar cadenas de reglas", "selected-rulechains": "{ count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} } seleccionadas", "open-rulechain": "Abrir cadena de reglas", - "assign-rulechains": "Asignar cadenas de reglas", "assign-new-rulechain": "Asignar nueva cadena de reglas", - "delete-rulechains": "Eliminar cadenas de reglas", - "unassign-rulechain": "Anular asignación de cadena de reglas", - "unassign-rulechains": "Anular asignación de cadenas de reglas", - "unassign-rulechain-title": "¿Está seguro de que desea desasignar la cadena de reglas '{{ruleChainName}}'?", + "edge-template-root": "Raíz de plantilla", + "assign-to-edge": "Asignar a Edge", + "edge-rulechain": "Cadena de reglas de borde", "unassign-rulechain-from-edge-text": "Después de la confirmación, la cadena de reglas quedará sin asignar y el borde no podrá acceder a ella", - "unassign-rulechains-from-edge-action-title": "Anular asignación {count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} } des bordes", + "unassign-rulechains-from-edge-title": "Estás seguro de desasignar { count, plural, 1 {1 cadena de reglas} other {# cadenas de reglas} }?", "unassign-rulechains-from-edge-text": "Después de la confirmación, todas las cadenas de reglas seleccionadas quedarán sin asignar y el borde no podrá acceder a ellas", "assign-rulechain-to-edge-title": "Asignar cadena (s) de reglas a borde", "assign-rulechain-to-edge-text": "Seleccione las cadenas de reglas para asignar al borde", @@ -2082,9 +2794,8 @@ "unset-auto-assign-to-edge": "Desmarcar asignar cadena de reglas a los bordes en la creación", "unset-auto-assign-to-edge-title": "¿Está seguro de que desea anular la asignación de la cadena de reglas de borde '{{ruleChainName}}' a los bordes en la creación?", "unset-auto-assign-to-edge-text": "Después de la confirmación, la cadena de reglas de borde ya no se asignará automáticamente a los bordes en la creación.", - "edge-template-root": "Raíz de plantilla", - "assign-to-edge": "Asignar a Edge", - "edge-rulechain": "Cadena de regla de borde" + "unassign-rulechain-title": "¿Está seguro de que desea desasignar la cadena de reglas '{{ruleChainName}}'?", + "unassign-rulechains": "Anular asignación de cadenas de reglas" }, "rulenode": { "details": "Detalles", @@ -2094,6 +2805,7 @@ "add": "Añadir nodo de reglas", "name": "Nombre", "name-required": "El nombre es requerido.", + "name-max-length": "Nombre debe ser menor de 256", "type": "Tipo", "description": "Descripción", "delete": "Eliminar nodo de reglas", @@ -2101,6 +2813,7 @@ "deselect-all-objects": "Deshacer selección de todos los nodos y conexiones", "delete-selected-objects": "Eliminar nodos y conexiones seleccionados", "delete-selected": "Eliminar seleccionado", + "create-nested-rulechain": "Crear cadena de reglas anidada", "select-all": "Seleccionar todos", "copy-selected": "Copiar seleccionado", "deselect-all": "Deshacer selección de todos", @@ -2131,6 +2844,8 @@ "type-external-details": "Interactuar con sistemas externos", "type-rule-chain": "Cadena de reglas", "type-rule-chain-details": "Reenvíar los mensajes entrantes a la cadena de reglas especificada", + "type-flow": "Flujo", + "type-flow-details": "Organiza el flujo de mensajes", "type-input": "Entrada", "type-input-details": "Entrada lógica de la Cadena de Reglas, reenvíar los mensajes entrantes al siguiente nodo de regla relacionado.", "type-unknown": "Desconocido", @@ -2154,12 +2869,89 @@ "timezone": "Zona Horaria", "select-timezone": "Seleccionar zona horaria", "no-timezones-matching": "No hay zonas horarias que coincidan con '{{timezone}}'.", - "timezone-required": "Se requiere zona horaria." + "timezone-required": "Se requiere zona horaria.", + "browser-time": "Hora del navegador" }, "queue": { - "select_name": "Selecciona el nombre de la cola", - "name": "Nombre Cola", - "name_required": "Necesario especificar el nombre de cola" + "queue-name": "Cola", + "no-queues-matching": "No se encontraron colas que coincidan con '{{queue}}'.", + "select_name": "Selecciona el nombre de la cola", + "name": "Nombre Cola", + "name_required": "Necesario especificar el nombre de cola", + "name-unique": "El nombre de cola ya existe!", + "queue-required": "Cola requerida!", + "topic-required": "Topic cola requerido!", + "poll-interval-required": "Intervalo de obtención requerido!", + "poll-interval-min-value": "El intervalo no debe ser menor de 1", + "partitions-required": "Particiones requeridas!", + "partitions-min-value": "El valor de particion no debe ser menor de 1", + "pack-processing-timeout-required": "Timeout de procesamiento", + "pack-processing-timeout-min-value": "Timeout de procesamiento no puede ser menor de 1", + "batch-size-required": "Tamaño del lote requerido!", + "batch-size-min-value": "El valor de tamaño de lote no puede ser menor de 1", + "retries-required": "Reintentos requerido!", + "retries-min-value": "El valor de reintentos no puede ser negativo", + "failure-percentage-required": "Porcentaje de fallos requerido!", + "failure-percentage-min-value": "Porcentaje de fallos no puede ser menor de 0", + "failure-percentage-max-value": "Porcentaje de fallos no puede ser mayor de 100", + "pause-between-retries-required": "Pausa entre reintentos requerido!", + "pause-between-retries-min-value": "Pausa mínima entre reintentos no puede ser menor de 1", + "max-pause-between-retries-required": "Pausa máxima entre reintentos requerido!", + "max-pause-between-retries-min-value": "Pausa máxima entre reintentos no puede ser menor de 1", + "submit-strategy-type-required": "Estrategia de envío requerida!", + "processing-strategy-type-required": "Estrategia de procesamiento requerida!", + "queues": "Colas", + "selected-queues": "{ count, plural, 1 {1 cola} other {# colas} } seleccionadas", + "delete-queue-title": "Estás seguro de borrar la cola '{{queueName}}'?", + "delete-queues-title": "Estás seguro de borrar { count, plural, 1 {1 cola} other {# colas} }?", + "delete-queue-text": "Atención, tras la confirmacion la cola y todos sus datos relacionados serán irrecuperables.", + "delete-queues-text": "Atención, tras la confirmación todas las colas se borrarán y no serán accesibles.", + "search": "Buscar cola", + "add" : "Añadir cola", + "details": "Detalles cola", + "topic": "Topic", + "submit-strategy": "Estrategia de envío", + "processing-strategy": "Estrategia de procesamiento", + "poll-interval": "Intervalo de obtención", + "partitions": "Particiones", + "consumer-per-partition": "Consumidores por partición", + "consumer-per-partition-hint": "Activar consumidores separados para cada partición", + "processing-timeout": "Timeout de procesamiento, ms", + "batch-size": "Tamaño de lote", + "retries": "Reintentos (0 - ilimitados)", + "failure-percentage": "Porcentaje de fallos", + "pause-between-retries": "Pausa entre reintentos", + "max-pause-between-retries": "Pausa máxima entre reintentos", + "delete": "Borrar cola", + "copyId": "Copiar Id de cola", + "idCopiedMessage": "La Id de cola se ha copiado al portapapeles", + "description": "Descripción", + "description-hint": "Este texto se mostrará en la descripción de la cola, en lugar de la estrategia seleccionada", + "alt-description": "Estrategia de envío: {{submitStrategy}}, Estrategia de procesamiento: {{processingStrategy}}", + "strategies": { + "sequential-by-originator-label": "Secuencial por iniciador", + "sequential-by-originator-hint": "El nuevo mensaje por ejemplo dispositivo A, no se enviará hasta que el mensaje anterior del dispositivo A sea admitido/procesado", + "sequential-by-tenant-label": "Secuencial por propietario", + "sequential-by-tenant-hint": "El nuevo mensaje, por ejemplo Propietario A, no se enviará hasta que el mensaje anterior del Propietario A sea admitido/procesado", + "sequential-label": "Secuencial", + "sequential-hint": "El nuevo mensaje no se enviará hasta que el mensaje anterior sea admitido/procesado", + "burst-label": "Ráfaga (Burst)", + "burst-hint": "Todos los mensajes se enviarán hacia las cadenas de reglas en el órden que lleguen", + "batch-label": "Lotes (Batch)", + "batch-hint": "El nuevo lote, no se enviará hasta que el anterior lote sea admitido/procesado", + "skip-all-failures-label": "Omitir todos los fallos", + "skip-all-failures-hint": "Ignorar todos los fallos", + "skip-all-failures-and-timeouts-label": "Omitir todos los fallos y timeouts", + "skip-all-failures-and-timeouts-hint": "Ignorar todos los fallos y timeouts", + "retry-all-label": "Reintentar todos", + "retry-all-hint": "Reintentar todos los mensajes del lote de procesamiento", + "retry-failed-label": "Reintentar fallidos", + "retry-failed-hint": "Reintentar todos los mensajes fallidos del lote de procesamiento", + "retry-timeout-label": "Timeout de reintentos", + "retry-timeout-hint": "Reintentar todos los mensajes que den timeout del lote de procesamiento", + "retry-failed-and-timeout-label": "Reintentar fallidos y timeouts", + "retry-failed-and-timeout-hint": "Reintentar todos los mensajes fallidos y que den timeout del lote de procesamiento" + } }, "tenant": { "tenant": "Propietario", @@ -2172,6 +2964,7 @@ "add-tenant-text": "Agregar nuevo propietario", "no-tenants-text": "Ningún propietario encontrado", "tenant-details": "Detalles del propietario", + "title-max-length": "Título debe ser menor de 256", "delete-tenant-title": "¿Quieres eliminar el propietario '{{tenantTitle}}'?", "delete-tenant-text": "Atención, tras la confirmación el propietario será eliminado y la información relacionada será irrecuperable.", "delete-tenants-title": "¿Quieres eliminar { count, plural, 1 {1 propietario} other {# propietarios} }?", @@ -2201,6 +2994,7 @@ "edit": "Editar perfil de propietario", "tenant-profile-details": "Detalles perfil de propietario", "no-tenant-profiles-text": "No se encontraron perfiles de propietario", + "name-max-length": "El nombre debe ser menor de 256", "search": "Buscar perfiles de propietario", "selected-tenant-profiles": "{ count, plural, 1 {1 perfil de propietario} other {# perfiles de propietario} } seleccionados", "no-tenant-profiles-matching": "No se han encontrado perfiles de propietario que coincidan con '{{entity}}'.", @@ -2223,6 +3017,12 @@ "set-default-tenant-profile-text": "Tras la confirmación, el perfil propietario será marcado por defecto y será usado por los nuevos perfiles propietarios que no tengan perfil específico.", "no-tenant-profiles-found": "No se encontraron perfiles de propietario.", "create-new-tenant-profile": "Crear un nuevo perfil!", + "create-tenant-profile": "Crear un nuevo perfil de propietario", + "import": "Importar perfil de propietario", + "export": "Exportar perfil de propietario", + "export-failed-error": "No se ha podido exportar el perfil de propietario: {{error}}", + "tenant-profile-file": "Archivo de perfil de propietario", + "invalid-tenant-profile-file-error": "No se ha podido importar el perfil de propietario: Estructura de datos inválida.", "maximum-devices": "Nº Máximo de dispositivos (0 - sin límite)", "maximum-devices-required": "Nº Máximo de dispositivos requerido.", "maximum-devices-range": "Nº Máximo de dispositivos no puede ser negativo", @@ -2241,6 +3041,12 @@ "maximum-rule-chains": "Nº Máximo de cadenas de reglas (0 - sin límite)", "maximum-rule-chains-required": "Nº Máximo de cadenas de reglas requerido.", "maximum-rule-chains-range": "Nº Máximo de cadenas de reglas no puede ser negativo", + "maximum-resources-sum-data-size": "Tamaño máximo de ficheros de recursos en bytes (0 - sin límite)", + "maximum-resources-sum-data-size-required": "Tamaño máximo de ficheros de recursos requerido.", + "maximum-resources-sum-data-size-range": "Tamaño máximo de ficheros de recursos no puede ser negativo", + "maximum-ota-packages-sum-data-size": "Tamaño máximo de paquetes OTA en bytes (0 - sin límite)", + "maximum-ota-package-sum-data-size-required": "Tamaño máximo de paquetes OTA requerido.", + "maximum-ota-package-sum-data-size-range": "Tamaño máximo de paquetes OTA no puede ser negativo", "transport-tenant-msg-rate-limit": "Tasa de mensajes de transporte por propietario.", "transport-tenant-telemetry-msg-rate-limit": "Tasa de mensajes de telemetría por propietario.", "transport-tenant-telemetry-data-points-rate-limit": "Tasa de datapoints por propietario.", @@ -2265,6 +3071,12 @@ "default-storage-ttl-days": "Días por defecto grabado TTL (0 - sin límite)", "default-storage-ttl-days-required": "Días por defecto TTL requerido.", "default-storage-ttl-days-range": "Días por defecto TTL no puede ser negativo", + "alarms-ttl-days": "Días de TTL alarmas (0 - sin límite)", + "alarms-ttl-days-required": "Días de TTL alarmas requerido", + "alarms-ttl-days-days-range": "Días de TTL alarmas no puede ser negativo", + "rpc-ttl-days": "Días TTL RPC (0 - sin límite)", + "rpc-ttl-days-required": "Días TTL RPC requerido", + "rpc-ttl-days-days-range": "Días TTL RPC no puede ser negativo", "max-rule-node-executions-per-message": "Nº Máximo de ejecuciones (cadena de reglas) por mensaje (0 - sin límite)", "max-rule-node-executions-per-message-required": "Nº Máximo de ejecuciones por mensaje requerido.", "max-rule-node-executions-per-message-range": "Nº Máximo de ejecuciones por mensaje no puede ser negativo", @@ -2273,20 +3085,47 @@ "max-emails-range": "Nº Máximo de emails no puede ser negativo", "max-sms": "Nº Máximo de mensajes SMS (0 - sin límite)", "max-sms-required": "Nº Máximo de mensajes SMS requerido.", - "max-sms-range": "Nº Máximo de mensajes SMS no puede ser negativo" + "max-sms-range": "Nº Máximo de mensajes SMS no puede ser negativo", + "max-created-alarms": "Nº Máximo de alarmas creadas (0 - sin límite)", + "max-created-alarms-required": "Nº Máximo de alarmas creadas requerido.", + "max-created-alarms-range": "Nº Máximo de alarmas creadas no puede ser negativo", + "no-queue": "No Queue configured", + "add-queue": "Add Queue", + "queues-with-count": "Queues ({{count}})" }, "timeinterval": { - "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segundos} }", - "minutes-interval": "{ minutes, plural, 1 {1 minuto} other {# minutos} }", - "hours-interval": "{ hours, plural, 1 {1 hora} other {# horas} }", - "days-interval": "{ days, plural, 1 {1 día} other {# días} }", - "days": "Días", - "hours": "Horas", - "minutes": "Minutos", - "seconds": "Segundos", - "advanced": "Avanzado" + "seconds-interval": "{ seconds, plural, 1 {1 segundo} other {# segundos} }", + "minutes-interval": "{ minutes, plural, 1 {1 minuto} other {# minutos} }", + "hours-interval": "{ hours, plural, 1 {1 hora} other {# horas} }", + "days-interval": "{ days, plural, 1 {1 día} other {# días} }", + "days": "Días", + "hours": "Horas", + "minutes": "Minutos", + "seconds": "Segundos", + "advanced": "Avanzado", + "predefined": { + "yesterday": "Ayer", + "day-before-yesterday": "Anteayer", + "this-day-last-week": "Hoy hace una semana", + "previous-week": "Semana anterior (Dom - Sáb)", + "previous-week-iso": "Semana anterior (Lun - Dom)", + "previous-month": "Mes anterior", + "previous-year": "Año anterior", + "current-hour": "Hora actual", + "current-day": "Día actual", + "current-day-so-far": "Día actual hasta ahora", + "current-week": "Semana actual (Dom - Sáb)", + "current-week-iso": "Semana actual (Lun - Dom)", + "current-week-so-far": "Semana actual hasta hoy (Dom - Sáb)", + "current-week-iso-so-far": "Semana actual hasta hoy (Lun - Dom)", + "current-month": "Mes actual", + "current-month-so-far": "Mes actual hasta hoy", + "current-year": "Año actual", + "current-year-so-far": "Año actual hasta ahora" + } }, "timeunit": { + "milliseconds": "Milisegundos", "seconds": "Segundos", "minutes": "Minutos", "hours": "Horas", @@ -2305,7 +3144,8 @@ "date-range": "Rango de fechas", "last": "Últimos(s)", "time-period": "Período de tiempo", - "hide": "Ocultar" + "hide": "Ocultar", + "interval": "Intervalo" }, "user": { "user": "Usuario", @@ -2354,7 +3194,9 @@ "disable-account": "Deshabilitar cuenta de usuario", "enable-account": "Habilitar cuenta de usuario", "enable-account-message": "¡La cuenta de usuario se ha habilitado correctamente!", - "disable-account-message": "¡La cuenta de usuario se deshabilitó correctamente!" + "disable-account-message": "¡La cuenta de usuario se deshabilitó correctamente!", + "copyId": "Copiar Id de usuario", + "idCopiedMessage": "El Id de usuario se ha copiado al portapapeles" }, "value": { "type": "Tipo de valor", @@ -2381,6 +3223,7 @@ "widget": { "widget-library": "Bibloteca de Widgets", "widget-bundle": "Paquetes de Widgets", + "all-bundles": "Todos los paquetes", "select-widgets-bundle": "Seleccionar paquete de widgets", "management": "Gestión de Widgets", "editor": "Editor de widgets", @@ -2420,6 +3263,13 @@ "css": "CSS", "settings-schema": "Esquema de configuración", "datakey-settings-schema": "Esquema de configuración de clave de datos", + "latest-datakey-settings-schema": "Esquema de últimos valores", + "widget-settings": "Ajustes de widget", + "description": "Descripción", + "image-preview": "Imagen previsualización", + "settings-form-selector": "Selector formulario de ajustes", + "data-key-settings-form-selector": "Selector formulario de ajustes claves de datos", + "latest-data-key-settings-form-selector": "Selector formulario de últimos valores", "javascript": "Javascript", "js": "JS", "remove-widget-type-title": "¿Eliminar el tipo del widget '{{widgetName}}'?", @@ -2433,7 +3283,10 @@ "export": "Exportar widget", "no-data": "No hay datos para mostrar en widget", "data-overflow": "El widget muestra {{count}} de {{total}} entidades", - "alarm-data-overflow": "El widget muestra alarmas para {{allowedEntities}} entidades (máximo permitido) de {{totalEntities}} entidades" + "alarm-data-overflow": "El widget muestra alarmas para {{allowedEntities}} entidades (máximo permitido) de {{totalEntities}} entidades", + "search": "Buscar widget", + "filter": "Filtro tipo de widget", + "loading-widgets": "Cargando widgets..." }, "widget-action": { "header-button": "Botón de encabezado widget", @@ -2442,18 +3295,52 @@ "open-dashboard": "Navegar hacia otro panel", "custom": "Acción personalizada", "custom-pretty": "Acción personalizada (con plantilla HTML)", + "mobile-action": "Acción en dispositivo móvil", "target-dashboard-state": "Estado de panel de destino", "target-dashboard-state-required": "Se requiere estado de panel de destino", "set-entity-from-widget": "Establecer entidad desde widget", "target-dashboard": "Panel de destino", "open-right-layout": "Abrir diseño de panel (derecho)(vista móvil)", + "state-display-type": "Opciones de display de panel", + "open-normal": "Normal", "open-in-separate-dialog": "Abrir en un diálogo separado", + "open-in-popover": "Abrir en popover", "dialog-title": "Título del diálogo", "dialog-hide-dashboard-toolbar": "Ocultar barra de herramientas en el diálogo", "dialog-width": "Ancho de diálogo en porcentaje relativo al ancho del viewport", "dialog-height": "Alto de diálogo en porcentaje relativo al alto del viewport", "dialog-size-range-error": "El tamaño del diálogo debe ser entre un rango de 1 a 100", - "open-new-browser-tab": "Abrir en una nueva pestaña" + "popover-preferred-placement": "Ubicación preferida popover", + "popover-placement-top": "Superior", + "popover-placement-topLeft": "Superior izquierda", + "popover-placement-topRight": "Superior derecha", + "popover-placement-right": "Derecha", + "popover-placement-rightTop": "Derecha superior", + "popover-placement-rightBottom": "Derecha inferior", + "popover-placement-bottom": "Inferior", + "popover-placement-bottomLeft": "Inferior izquierda", + "popover-placement-bottomRight": "Inferior derecha", + "popover-placement-left": "Izquierda", + "popover-placement-leftTop": "Izquierda superior", + "popover-placement-leftBottom": "Izquierda inferior", + "popover-hide-on-click-outside": "Ocultar en click fuera del popover", + "popover-hide-dashboard-toolbar": "Ocultar caja de herramientas en popover", + "popover-width": "Ancho de popover en unidades de navegador (ej. 100px, 25vw)", + "popover-height": "Altura de popover en unidades de navegador (ej. 100px, 25vh)", + "popover-style": "Estilo de popover", + "open-new-browser-tab": "Abrir en una nueva pestaña", + "mobile": { + "action-type": "Tipo de acción móvil", + "action-type-required": "Tipo de acción móvil requerida", + "take-picture-from-gallery": "Tomar foto de galería", + "take-photo": "Tomar foto", + "map-direction": "Abrir indicaciones en mapa", + "map-location": "Abrir localización en mapa", + "scan-qr-code": "Escanear código QR", + "make-phone-call": "Hacer llamada telefónica", + "get-location": "Obtener localización del teléfono", + "take-screenshot": "Obtener captura de pantalla" + } }, "widgets-bundle": { "current": "Paquete actual", @@ -2462,6 +3349,9 @@ "delete": "Eliminar paquete de widgets", "title": "Título", "title-required": "Título requerido.", + "title-max-length": "El título debe ser menor de 256", + "description": "Descripción", + "image-preview": "Imagen previsualización", "add-widgets-bundle-text": "Agregar nuevo paquete de widgets", "no-widgets-bundles-text": "Ningún paquete de widgets encontrado", "empty": "Paquete de widgets vacío.", @@ -2483,7 +3373,8 @@ "invalid-widgets-bundle-file-error": "Imposible importar paquete de widgets: Estructura de datos inválida.", "search": "Buscar paquete de widgets", "selected-widgets-bundles": "{ count, plural, 1 {1 paquete de widgets} other {# paquetes de widgets} } seleccionados", - "open-widgets-bundle": "Abrir paquete de widgets" + "open-widgets-bundle": "Abrir paquete de widgets", + "loading-widgets-bundles": "Cargando paquete de widgets..." }, "widget-config": { "data": "Datos", @@ -2500,15 +3391,18 @@ "padding": "Relleno", "margin": "Margen", "widget-style": "Estilo de widget", + "widget-css": "CSS de widget", "title-style": "Estilo de título", "mobile-mode-settings": "Ajustes móvil.", "order": "Orden", "height": "Altura", + "mobile-hide": "Ocultar widget en modo móvil", "units": "Caracter especial a mostrar en el siguiente valor", "decimals": "Números de dígitos después de la coma", "timewindow": "Ventana de tiempo", "use-dashboard-timewindow": "Usar ventana de tiempo del Panel", "display-timewindow": "Mostrar ventana de tiempo", + "legend": "Leyenda", "display-legend": "Mostrar leyenda", "datasources": "Set de datos", "maximum-datasources": "Un máximo de { count, plural, 1 {1 set de datos es permitido.} other {# set de datos son permitidos} }", @@ -2529,15 +3423,22 @@ "action-name-required": "Nombre de accion requerido.", "action-name-not-unique": "Existe una acción con el mismo nombre.
El nombre de acción debe ser único dentro de la misma fuente de acción (origen).", "action-icon": "Icono", + "show-hide-action-using-function": "Mostrar/Ocultar acción usando función", "action-type": "Tipo", "action-type-required": "Tipo de acción requerido.", "edit-action": "Editar acción", "delete-action": "Borrar acción", "delete-action-title": "Borrar acción de widget", "delete-action-text": "Eliminar la acción de widget con el nombre '{{actionName}}'?", - "display-icon": "Mostrar icono del título", + "title-icon": "Título de icono", + "display-icon": "Mostrar título de icono", "icon-color": "Color del icono", - "icon-size": "Tamaño del icono" + "icon-size": "Tamaño del icono", + "advanced-settings": "Ajustes avanzados", + "data-settings": "Ajustes de datos", + "no-data-display-message": "\"No hay datos que mostrar\" mensaje alternativo", + "data-page-size": "Nº Máximo de entidades por origen de datos", + "settings-component-not-found": "Componente de ajustes no encontrado para el selector '{{selector}}'" }, "widget-type": { "import": "Importar tipo de widget", @@ -2548,7 +3449,146 @@ "invalid-widget-type-file-error": "No se puede importar tipo de widget: Estructura de datos del tipo de widget es inválida." }, "widgets": { + "chart": { + "common-settings": "Ajustes comunes", + "enable-stacking-mode": "Activar modo de apilamiento (stacking)", + "line-shadow-size": "Tamaño de sombra (línea)", + "display-smooth-lines": "Mostrar líneas suaves (curvas)", + "default-bar-width": "Ancho de barra por defecto para datos no agregados (millisegundos)", + "bar-alignment": "Alineación barra", + "bar-alignment-left": "Izquierda", + "bar-alignment-right": "Derecha", + "bar-alignment-center": "Centro", + "default-font-size": "Tamaño de fuente por defecto", + "default-font-color": "Color de fuente por defecto", + "thresholds-line-width": "Ancho de línea por defecto para todos los umbrales", + "tooltip-settings": "Ajustes de sugerencias (tooltip)", + "show-tooltip": "Mostrar sugerencias", + "hover-individual-points": "Hover sobre puntos individuales", + "show-cumulative-values": "Mostrar valores acumulados en modo apilado", + "hide-zero-false-values": "Ocultar valores cero/false en sugerencias", + "tooltip-value-format-function": "Función de formateo de valores en sugerencias (tooltip)", + "grid-settings": "Ajustes de cuadrícula", + "show-vertical-lines": "Mostrar líneas verticales", + "show-horizontal-lines": "Mostrar líneas horizontales", + "grid-outline-border-width": "Ancho de cuadrícula/contorno en px", + "primary-color": "Color primario", + "background-color": "Color de fondo", + "ticks-color": "Color de ticks", + "xaxis-settings": "Ajustes eje X", + "axis-title": "Título de eje", + "xaxis-tick-labels-settings": "Ajustes de etiquetas en ticks eje X", + "show-tick-labels": "Mostrar etiquetas en ticks", + "yaxis-settings": "Ajustes eje Y", + "min-scale-value": "Valor mínimo en la escala", + "max-scale-value": "Valor máximo en la escala", + "yaxis-tick-labels-settings": "Ajustes de etiquetas en ticks eje Y", + "tick-step-size": "Tamaño de paso entre ticks", + "number-of-decimals": "Número de decimales", + "ticks-formatter-function": "Función de formateo de ticks", + "comparison-settings": "Ajustes de comparación", + "enable-comparison": "Activar comparación", + "time-for-comparison": "Período de comparación", + "time-for-comparison-previous-interval": "Intervalo anterior (por defecto)", + "time-for-comparison-days": "Hace un día", + "time-for-comparison-weeks": "Hace una semana", + "time-for-comparison-months": "Hace un mes", + "time-for-comparison-years": "Hace un año", + "time-for-comparison-custom-interval": "Intervalo personalizado", + "custom-interval-value": "Valor de intervalo personalizado (ms)", + "comparison-x-axis-settings": "Ajustes comparación eje X", + "axis-position": "Posición eje", + "axis-position-top": "Superior (por defecto)", + "axis-position-bottom": "Inferior", + "custom-legend-settings": "Ajustes leyenda", + "enable-custom-legend": "Activar leyenda personalizada (habilita poder usar valores de atributos/timeseries en las etiquetas)", + "key-name": "Nombre clave", + "key-name-required": "Nombre clave requerido", + "key-type": "Tipo clave", + "key-type-attribute": "Atributo", + "key-type-timeseries": "Timeseries", + "label-keys-list": "Lista de claves para usar en etiquetas", + "no-label-keys": "No hay claves configuradas", + "add-label-key": "Añadir nueva clave", + "line-width": "Ancho de línea", + "color": "Color", + "data-is-hidden-by-default": "Ocultar datos por defecto", + "disable-data-hiding": "Desactivar ocultación de datos", + "remove-from-legend": "Quitar clave de la leyenda", + "exclude-from-stacking": "Excluir del modo apilado(disponible en el modo \"Apilado\")", + "line-settings": "Ajustes de línea", + "show-line": "Mostrar línea", + "fill-line": "Rellenar línea", + "points-settings": "Ajustes de puntos", + "show-points": "Mostrar puntos", + "points-line-width": "Ancho de línea en puntos", + "points-radius": "Radio de los puntos", + "point-shape": "Forma del punto", + "point-shape-circle": "Círculo", + "point-shape-cross": "Cruz", + "point-shape-diamond": "Diamante", + "point-shape-square": "Cuadrado", + "point-shape-triangle": "Triángulo", + "point-shape-custom": "Función personalizada", + "point-shape-draw-function": "Función de forma del punto", + "show-separate-axis": "Mostrar eje separado", + "axis-position-left": "Izquieda", + "axis-position-right": "Derecha", + "thresholds": "Umbrales", + "no-thresholds": "No hay umbrales configurados", + "add-threshold": "Añadir nuevo umbral", + "show-values-for-comparison": "Mostrar valores históricos para su comparación", + "comparison-values-label": "Etiqueta de valores históricos", + "threshold-settings": "Ajustes de umbrales", + "use-as-threshold": "Usar valor de clave como umbral", + "threshold-line-width": "Ancho de línea (para umbral)", + "threshold-color": "Color umbral", + "common-pie-settings": "Ajustes comunes diagrama de sectores", + "radius": "Radio", + "inner-radius": "Radio interior", + "tilt": "Inclinación", + "stroke-settings": "Ajustes de trazo", + "width-pixels": "Ancho (pixels)", + "show-labels": "Mostrar etiquetas", + "animation-settings": "Ajustes de animación", + "animated-pie": "Activar animación (experimental)", + "border-settings": "Ajustes de bordes", + "border-width": "Ancho de borde", + "border-color": "Color de borde", + "legend-settings": "Ajustes de leyenda", + "display-legend": "Mostrar leyenda", + "labels-font-color": "Color de texto en leyenda" + }, + "dashboard-state": { + "dashboard-state-settings": "Ajustes estado de panel", + "dashboard-state": "Id de estado panel", + "autofill-state-layout": "Auto-rellenar altura por defecto (obtenida del estado)", + "default-margin": "Márgen entre widgets por defecto", + "default-background-color": "Color de fondo por defecto", + "sync-parent-state-params": "Sincronizar parámetros de estado con el panel padre" + }, "date-range-navigator": { + "date-range-picker-settings": "Ajustes del selector de fechas", + "hide-date-range-picker": "Ocultar el selector de fechas", + "picker-one-panel": "Selector de fechas para un panel", + "picker-auto-confirm": "Auto-confirmar en selector de fechas", + "picker-show-template": "Mostrar plantilla de selector de fechas", + "first-day-of-week": "Primer día de la semana", + "interval-settings": "Ajustes de intervalo", + "hide-interval": "Ocultar intervalo", + "initial-interval": "Intervalo inicial", + "interval-hour": "Hora", + "interval-day": "Día", + "interval-week": "Semana", + "interval-two-weeks": "2 semanas", + "interval-month": "Mes", + "interval-three-months": "3 meses", + "interval-six-months": "6 meses", + "step-settings": "Ajustes de paso", + "hide-step-size": "Ocultar tamaño de paso", + "initial-step-size": "Tamaño de paso inicial", + "hide-labels": "Ocultar etiquetas", + "use-session-storage": "Usar almacenamiento de sesión", "localizationMap": { "Sun": "Dom.", "Mon": "Lun.", @@ -2605,6 +3645,176 @@ "Ok": "Ok" } }, + "entities-hierarchy": { + "hierarchy-data-settings": "Ajustes de datos de jerarquía", + "relations-query-function": "Función de obtención de relaciones", + "has-children-function": "El nodo tiene una función hija", + "node-state-settings": "Ajustes estado nodo", + "node-opened-function": "Función por defecto al abrir nodo", + "node-disabled-function": "Función con nodo desactivado", + "display-settings": "Mostrar ajustes", + "node-icon-function": "Función de icono nodo", + "node-text-function": "Función de texto nodo", + "sort-settings": "Ajustes de ordenación", + "nodes-sort-function": "Función de ordenación" + }, + "edge": { + "display-default-title": "Mostrar título por defecto" + }, + "gateway": { + "general-settings": "Ajustes generales", + "widget-title": "Título del widget", + "default-archive-file-name": "Nombre del fichero por defecto", + "device-type-for-new-gateway": "Tipo de dispositivo para nuevo gateway", + "messages-settings": "Ajustes de mensajes", + "save-config-success-message": "Mensaje de éxito grabando configuración", + "device-name-exists-message": "Mensaje de texto cuando el nombre del dispositivo ya exista", + "gateway-title": "Formulario Gateway", + "read-only": "Solo lectura", + "events-title": "Título del formulario de eventos", + "events-filter": "Filtro de eventos", + "event-key-contains": "La clave de evento contiene..." + }, + "gauge": { + "default-color": "Color por defecto", + "radial-gauge-settings": "Ajustes de indicador radial", + "ticks-settings": "Ajustes de ticks", + "min-value": "Valor mínimo", + "max-value": "Valor máximo", + "start-ticks-angle": "Ángulo de inicio ticks", + "ticks-angle": "Ángulo Ticks", + "major-ticks-count": "Nº de ticks principales", + "major-ticks-color": "Color Nº de ticks principales", + "minor-ticks-count": "Nº de ticks secundarios", + "minor-ticks-color": "Color Nº de ticks secundarios", + "tick-numbers-font": "Fuente del tick", + "unit-title-settings": "Ajustes de unidad (título)", + "show-unit-title": "Mostrar unidades (título)", + "unit-title": "Título de unidad", + "title-font": "Fuente de texto del título", + "units-settings": "Ajustes de unidades", + "units-font": "Fuente de texto de las unidades", + "value-box-settings": "Ajustes de valor", + "show-value-box": "Mostrar valor", + "value-int": "Nº de dígitos para la parte entera del valor", + "value-font": "Fuente de texto del valor", + "value-box-rect-stroke-color": "Color del trazo del rectángulo (valor)", + "value-box-rect-stroke-color-end": "Color del trazo del rectángulo (valor) - gradiente final", + "value-box-background-color": "Color de fondo del valor", + "value-box-shadow-color": "Color de sombra del valor", + "plate-settings": "Ajustes de la placa", + "show-plate-border": "Mostrar borde de la placa", + "plate-color": "Color de la placa", + "needle-settings": "Ajustes de la aguja", + "needle-circle-size": "Tamaño del círculo de la aguja", + "needle-color": "Color de la aguja", + "needle-color-end": "Color de la aguja - gradiente final", + "needle-color-shadow-up": "Color de sombreado de la mitad superior de la aguja", + "needle-color-shadow-down": "Color de sombra de la aguja", + "highlights-settings": "Ajustes de resalto", + "highlights-width": "Ancho del resalto", + "highlights": "Resaltos", + "highlight-from": "De", + "highlight-to": "A", + "highlight-color": "Color", + "no-highlights": "No hay resaltos configurados", + "add-highlight": "Añadir resalto", + "animation-settings": "Ajustes de animación", + "enable-animation": "Activar animación", + "animation-duration": "Duración de animación", + "animation-rule": "Regla de animación", + "animation-linear": "Lineal", + "animation-quad": "Quad", + "animation-quint": "Quint", + "animation-cycle": "Ciclo (cycle)", + "animation-bounce": "Rebote (bounce)", + "animation-elastic": "Elastic", + "animation-dequad": "Dequad", + "animation-dequint": "Dequint", + "animation-decycle": "Decycle", + "animation-debounce": "Debounce", + "animation-delastic": "Delastic", + "linear-gauge-settings": "Ajustes de indicador lineal", + "bar-stroke-width": "Ancho del trazo", + "bar-stroke-color": "Color del trazo", + "bar-background-color": "Color de fondo del indicador", + "bar-background-color-end": "Color de fondo del indicador - gradiente final", + "progress-bar-color": "Color de la barra de progreso", + "progress-bar-color-end": "Color de la barra de progreso - gradiente final", + "major-ticks-names": "Nombre de ticks principales", + "show-stroke-ticks": "Mostrar trazo de ticks", + "major-ticks-font": "Fuente de ticks principales", + "border-color": "Color del borde", + "border-width": "Ancho del borde", + "needle-circle-color": "Color del círculo de la aguja", + "animation-target": "Destino de la animación", + "animation-target-needle": "Aguja", + "animation-target-plate": "Placa", + "common-settings": "Ajustes comunes del indicador", + "gauge-type": "Tipo de indicador", + "gauge-type-arc": "Arco", + "gauge-type-donut": "Donut", + "gauge-type-horizontal-bar": "Barra horizontal", + "gauge-type-vertical-bar": "Barra vertical", + "donut-start-angle": "Ángulo de inicio", + "bar-settings": "Ajustes de barra indicadora", + "relative-bar-width": "Ancho relativo", + "neon-glow-brightness": "Efecto brillo de neon, (0-100), 0 - desactiva efecto", + "stripes-thickness": "Grosor de las rayas, 0 - sin rayas", + "rounded-line-cap": "Mostrar tapa de línea redondeada", + "bar-color-settings": "Ajustes de color de barra", + "use-precise-level-color-values": "Usar niveles precisos de color", + "bar-colors": "Colores de la barra, del más bajo al más alto", + "color": "Color", + "no-bar-colors": "No hay colores configurados", + "add-bar-color": "Añadir color", + "from": "De", + "to": "A", + "fixed-level-colors": "Colores de barra usando valores límite", + "gauge-title-settings": "Ajustes de título del indicador", + "show-gauge-title": "Mostrar título de indicador", + "gauge-title": "Título de indicador", + "gauge-title-font": "Fuente del título del indicador", + "unit-title-and-timestamp-settings": "Ajustes del título de unidades y timestamp", + "show-timestamp": "Mostrar valor timestamp", + "timestamp-format": "Formato timestamp", + "label-font": "Fuente de la etiqueta que se muestra bajo el valor", + "value-settings": "Ajustes del valor", + "show-value": "Mostrar texto del valor", + "min-max-settings": "Etiqueta mínimo/máximo", + "show-min-max": "Mostrar valores mínimos y máximos", + "min-max-font": "Fuente de los valores mínimo y máximo", + "show-ticks": "Mostrar ticks", + "tick-width": "Ancho de tick", + "tick-color": "Color de tick", + "tick-values": "Valores de tick", + "no-tick-values": "No hay valores configurados", + "add-tick-value": "Añadir valor de tick" + }, + "gpio": { + "pin": "Pin", + "label": "Etiqueta", + "row": "Fila", + "column": "Columna", + "color": "Color", + "panel-settings": "Ajustes de panel", + "background-color": "Color de fondo", + "gpio-switches": "switches GPIO", + "no-gpio-switches": "No hay switches GPIO configurados", + "add-gpio-switch": "Añadir switch GPIO", + "gpio-status-request": "Solicitud estado GPIO", + "method-name": "Nombre del método RPC", + "method-body": "Cuerpo del método RPC", + "gpio-status-change-request": "Solicitud de cambio de estado GPIO", + "parse-gpio-status-function": "Función de parseado de estado GPIO", + "gpio-leds": "Leds GPIO", + "no-gpio-leds": "No hay Leds GPIO configurados", + "add-gpio-led": "Añadir led GPIO" + }, + "html-card": { + "html": "HTML", + "css": "CSS" + }, "input-widgets": { "attribute-not-allowed": "El parámetro de atributo no se puede usar en este widget", "blocked-location": "La función de geolocalización está bloqueada en tu navegador", @@ -2649,7 +3859,570 @@ "update-successful": "Actualización exitosa", "update-attribute": "Actualizar atributo", "update-timeseries": "Actualizar series de tiempo", - "value": "Valor" + "value": "Valor", + "general-settings": "Ajustes Generales", + "widget-title": "Título del widget", + "claim-button-label": "Etiqueta del botón de reclamar", + "show-secret-key-field": "Mostrar el campo 'Clave Secreta'", + "labels-settings": "Ajustes de etiquetas", + "show-labels": "Mostrar etiquetas", + "device-name-label": "Etiqueta para el campo de entrada 'Nombre de Dispositivo'", + "secret-key-label": "Etiqueta para el campo de entrara 'Clave Secreta'", + "messages-settings": "Ajustes de mensajes", + "claim-device-success-message": "Mensaje a mostrar cuando el dispositivo se haya reclamado ok", + "claim-device-not-found-message": "Mensaje a mostrar cuando el dispositivo no se encuentre", + "claim-device-failed-message": "Mensaje a mostrar cuando ocurra un error reclamando el dispositivo", + "claim-device-name-required-message": "Mensaje de error a mostrar con 'Nombre de dispositivo requerido'", + "claim-device-secret-key-required-message": "Mensaje de error a mostrar con 'Clave Secreta requerida'", + "show-label": "Mostrar etiqueta", + "label": "Etiqueta", + "required": "Requerido", + "required-error-message": "Error a mostrar con campo 'Requerido'", + "show-result-message": "Mensaje para mostrar resultado", + "integer-field-settings": "Ajustes de campos tipo entero", + "min-value": "Valor Mínimo", + "max-value": "Valor Máximo", + "double-field-settings": "Ajustes de campos tipo double", + "text-field-settings": "Ajustes de campos tipo texto", + "min-length": "Longitud mínima", + "max-length": "Longitud máxima", + "checkbox-settings": "Ajustes de campos tipo checkbox", + "true-label": "Etiqueta checked", + "false-label": "Etiqueta unchecked", + "image-input-settings": "Ajustes de campos tipo entrada de imagen", + "display-preview": "Mostrar previsualización", + "display-clear-button": "Mostrar botón de borrar", + "display-apply-button": "Mostrar botón de aplicar", + "display-discard-button": "Mostrar botón de descartar", + "datetime-field-settings": "Ajustes de campos tipo Fecha/Hora", + "display-time-input": "Mostrar entrada de hora", + "latitude-key-name": "Nombre clave latitud", + "longitude-key-name": "Nombre clave longitud", + "show-get-location-button": "Mostrar botón 'Obtener localización actual'", + "use-high-accuracy": "Usar alta precisión", + "location-fields-settings": "Ajustes de campos de localización", + "latitude-label": "Etiqueta para latitud", + "longitude-label": "Etiqueta para longitud", + "input-fields-alignment": "Alineado de campos de entrada", + "input-fields-alignment-column": "Columna (por defecto)", + "input-fields-alignment-row": "Fila", + "latitude-field-required": "Campo latitud requerido", + "longitude-field-required": "Campo longitud requerido", + "attribute-settings": "Ajustes de atributos", + "widget-mode": "Modo del widget", + "widget-mode-update-attribute": "Actualizar atributo", + "widget-mode-update-timeseries": "Actualizar timeseries", + "attribute-scope": "Alcance de atributos", + "attribute-scope-server": "Atributos de servidor", + "attribute-scope-shared": "Atributos compartidos", + "value-required": "Valor requerido", + "image-settings": "Ajustes de imagen", + "image-format": "Formato de imagen", + "image-format-jpeg": "JPEG", + "image-format-png": "PNG", + "image-format-webp": "WEBP", + "image-quality": "Calidad de imagen que usa compresión con pérdida como jpeg y webp", + "max-image-width": "Máximo ancho de imagen", + "max-image-height": "Máximo alto de imagen", + "action-buttons": "Botones de acción", + "show-action-buttons": "Mostrar botones de acción", + "update-all-values": "Actualizar todos los valores, no sólo los modificados", + "save-button-label": "Etiqueta de botón 'GRABAR'", + "reset-button-label": "Etiqueta de botón 'DESHACER'", + "group-settings": "Ajustes de grupo", + "show-group-title": "Mostrar título para el grupo de campos relacionados con diferentes entidades", + "group-title": "Título del grupo", + "fields-alignment": "Alineado de campos", + "fields-alignment-row": "Fila (por defecto)", + "fields-alignment-column": "Columna", + "fields-in-row": "Número de campos en la fila", + "option-value": "Valor (escribe 'null' para crear una opción vacía)", + "option-label": "Etiqueta", + "hide-input-field": "Ocultar campo de entrada", + "datakey-type": "Tipo de clave de datos", + "datakey-type-server": "Atributo de servidor (por defecto)", + "datakey-type-shared": "Atributo compartido", + "datakey-type-timeseries": "Timeseries", + "datakey-value-type": "Tipo de valor de la clave de datos", + "datakey-value-type-string": "String", + "datakey-value-type-double": "Double", + "datakey-value-type-integer": "Entero", + "datakey-value-type-boolean-checkbox": "Boolean (Checkbox)", + "datakey-value-type-boolean-switch": "Boolean (Switch)", + "datakey-value-type-date-time": "Fecha & Hora", + "datakey-value-type-date": "Fecha", + "datakey-value-type-time": "Hora", + "datakey-value-type-select": "Selección", + "value-is-required": "Valor requerido", + "ability-to-edit-attribute": "Posibilidad de editar atributo", + "ability-to-edit-attribute-editable": "Editable (por defecto)", + "ability-to-edit-attribute-disabled": "Desactivado", + "ability-to-edit-attribute-readonly": "Sólo lectura", + "disable-on-datakey-name": "Desactivar cuando otra clave de datos sea false (especificar nombre de clave de datos)", + "slide-toggle-settings": "Ajustes de deslizador", + "slide-toggle-label-position": "Posición de etiqueta", + "slide-toggle-label-position-after": "Después", + "slide-toggle-label-position-before": "Antes", + "select-options": "Seleccionar opciones", + "no-select-options": "No hay opciones configuradas", + "add-select-option": "Añadir opción", + "numeric-field-settings": "Ajustes de campos numéricos", + "step-interval": "Pasos entre valores (intervalo)", + "error-messages": "Mensajes de erro", + "min-value-error-message": "Mensaje de error de 'Valor Mínimo'", + "max-value-error-message": "Mensaje de error de 'Valor Máximo'", + "invalid-date-error-message": "Mensaje de erro de 'Fecha Inválida'", + "icon-settings": "Ajustes de iconos", + "use-custom-icon": "Usar icono personalizado", + "input-cell-icon": "Icono a mostrar antes del campo de entrada", + "value-conversion-settings": "Ajustes de conversión de valor", + "get-value-settings": "Ajustes de obtención de valores", + "use-get-value-function": "Usar función getValue", + "get-value-function": "Función getValue", + "set-value-settings": "Ajustes de establecimiento de valores", + "use-set-value-function": "Usar función setValue", + "set-value-function": "Función setValue" + }, + "invalid-qr-code-text": "Texto de entrara inválido para el código QR. La entrada debe ser de tipo string", + "qr-code": { + "use-qr-code-text-function": "Usar función de texto QR", + "qr-code-text-pattern": "Patrón del código QR (por ej. '${entityName} | ${keyName} - texto adicional.')", + "qr-code-text-pattern-required": "Se requiere patrón del código QR.", + "qr-code-text-function": "Función del código QR" + }, + "label-widget": { + "label-pattern": "Patrón", + "label-pattern-hint": "Ayuda: por ej. 'Texto ${keyName} unidades.' o ${#<key index>} unidades'", + "label-pattern-required": "Se requiere patrón", + "label-position": "Posición (Porcentaje relativo al fondo)", + "x-pos": "X", + "y-pos": "Y", + "background-color": "Color de fondo", + "font-settings": "Ajustes de fuente", + "background-image": "Imagen de fondo", + "labels": "Etiquetas", + "no-labels": "No hay etiquetas configuradas", + "add-label": "Añadir etiqueta" + }, + "navigation": { + "title": "Título", + "navigation-path": "Ruta de navegación", + "filter-type": "Tipo de filtro", + "filter-type-all": "Todos los objetos", + "filter-type-include": "Incluir objetos", + "filter-type-exclude": "Excluir objetos", + "items": "Objetos", + "enter-urls-to-filter": "Especificar URLs a filtrar..." + }, + "persistent-table": { + "rpc-id": "ID RPC", + "message-type": "Tipo de mensaje", + "method": "Método", + "params": "Parémetros", + "created-time": "Hora de creación", + "expiration-time": "Hora de expiración", + "retries": "Reintentos", + "status": "Estado", + "filter": "Filtro", + "refresh": "Actualizar", + "add": "Añadir petición RPC", + "details": "Detalles", + "delete": "Borrar", + "delete-request-title": "Borrar petición RPC persistente", + "delete-request-text": "Estas seguro de borrar la petición?", + "details-title": "Detalles ID RPC: ", + "additional-info": "Información adicional", + "response": "Respuesta", + "any-status": "Cualquier estado", + "rpc-status-list": "Lista de estados RPC", + "no-request-prompt": "No hay peticiones a mostrar", + "send-request": "Enviar petición", + "add-title": "Crear una petición RPC persistente", + "method-error": "Se requiere método.", + "timeout-error": "El valor mínimo de timeout es 5000 (5 segundos).", + "white-space-error": "No se permiten espacios en blanco.", + "rpc-status": { + "QUEUED": "EN COLA", + "SENT": "ENVIADO", + "DELIVERED": "ENTREGADO", + "SUCCESSFUL": "CORRECTO", + "TIMEOUT": "TIMEOUT", + "EXPIRED": "EXPIRADO", + "FAILED": "FALLO" + }, + "rpc-search-status-all": "TODOS", + "message-types": { + "false": "Two-way", + "true": "One-way" + }, + "general-settings": "Ajustes Generales", + "enable-filter": "Activar filtro", + "enable-sticky-header": "Mostrar encabezado mientras se hace scroll", + "enable-sticky-action": "Mostrar columna de acciones mientras se hace scroll", + "display-request-details": "Mostrar detalles de petición", + "allow-send-request": "Permitir enviar petición RPC", + "allow-delete-request": "Permitir borrar petición", + "columns-settings": "Ajustes de columnas", + "display-columns": "Columnas a mostrar", + "column": "Columna", + "no-columns-found": "No se encontraron columnas", + "no-columns-matching": "'{{column}}' no encontrada." + }, + "rpc": { + "value-settings": "Ajustes de valor", + "initial-value": "Valor inicial", + "retrieve-value-settings": "Obtener ajustes valores on/off", + "retrieve-value-method": "Obtener valor usando método", + "retrieve-value-method-none": "No obtener", + "retrieve-value-method-rpc": "Método para llamada RPC de obtención de valor", + "retrieve-value-method-attribute": "Suscribir por atributo", + "retrieve-value-method-timeseries": "Suscribir por timeseries", + "attribute-value-key": "Clave de atributo", + "timeseries-value-key": "Clave de timeseries", + "get-value-method": "Metodo para obtener valor vía RPC", + "parse-value-function": "Función de parseo de valor", + "update-value-settings": "Ajustes de actualización de valor", + "set-value-method": "Método para establecer valor vía RPC", + "convert-value-function": "Función de conversión", + "rpc-settings": "Ajustes RPC", + "request-timeout": "Timeout de petición RPC (ms)", + "persistent-rpc-settings": "Ajustes de RPC persistente", + "request-persistent": "Petición RPC persistente", + "persistent-polling-interval": "Intervalo de sondeo (ms) para obtener respuesta del comando RPC persistente", + "common-settings": "Ajustes comunes", + "switch-title": "Título del switch", + "show-on-off-labels": "Mostrar etiquetas on/off", + "slide-toggle-label": "Etiqueta de interruptor deslizante", + "label-position": "Posición de etiqueta", + "label-position-before": "Antes", + "label-position-after": "Después", + "slider-color": "Color del deslizador", + "slider-color-primary": "Primario", + "slider-color-accent": "Acento", + "slider-color-warn": "Aviso", + "button-style": "Estilo de botón", + "button-raised": "Botón levantado", + "button-primary": "Color primario", + "button-background-color": "Color de fondo", + "button-text-color": "Color de texto", + "widget-title": "Título del widget", + "button-label": "Etiqueta del botón", + "device-attribute-scope": "Alcance de atributos del dispositivo", + "server-attribute": "Atributos de servidor", + "shared-attribute": "Atributos compartidos", + "device-attribute-parameters": "Parámetros de atributos del dispositivo", + "is-one-way-command": "Es un comando de una vía (one way)", + "rpc-method": "Método RPC", + "rpc-method-params": "Parámetros método RPC", + "show-rpc-error": "Mostrar errores de ejecución de RPC", + "led-title": "Título LED", + "led-color": "Color LED", + "check-status-settings": "Ajustes de comprobación de estado", + "perform-rpc-status-check": "Realizar comprobación del dispositivo RPC", + "retrieve-led-status-value-method": "Obtener estado del led usando método", + "led-status-value-attribute": "Atributo del dispositivo que contiene el valor del estado del led", + "led-status-value-timeseries": "Timeseries del dispositivo que contiene el valor del estado del led", + "check-status-method": "Método RPC para chequear el estado del dispositivo", + "parse-led-status-value-function": "Función de parseo para el estado del led", + "knob-title": "Título de mando", + "min-value": "Valor mínimo", + "max-value": "Valor máximo" + }, + "maps": { + "select-entity": "Seleccionar entidad", + "select-entity-hint": "Ayuda: tras la selección haz click en el mapa para establecer la posición", + "tooltips": { + "placeMarker": "Click para colocar la entidad '{{entityName}}'", + "firstVertex": "Polígono para la entidad '{{entityName}}': click para colocar el primer punto", + "firstVertex-cut": "Click para colocar el primer punto", + "continueLine": "Polígono para la entidad '{{entityName}}': click para continuar dibujando", + "continueLine-cut": "Click para continuar dibujando", + "finishLine": "Click en cualquier marcador existente para finalizar", + "finishPoly": "Polígono para la entidad '{{entityName}}': click en el primer marcador para finalizar y grabar los cambios", + "finishPoly-cut": "Click en el primer marcador para finalizar y grabar los cambios", + "finishRect": "Polígono para la entidad '{{entityName}}': click para finalizar y grabar los cambios", + "startCircle": "Círculo para la entidad '{{entityName}}': click para establecer el centro del círculo", + "finishCircle": "Círculo para la entidad '{{entityName}}': click para finalizar el círculo", + "placeCircleMarker": "Click para colocar el marcador del círculo" + }, + "actions": { + "finish": "Finalizar", + "cancel": "Cancelar", + "removeLastVertex": "Quitar último punto" + }, + "buttonTitles": { + "drawMarkerButton": "Establecer entidad", + "drawPolyButton": "Crear polígono", + "drawLineButton": "Crear polilínea", + "drawCircleButton": "Crear círculo", + "drawRectButton": "Crear rectángulo", + "editButton": "Modo de edición", + "dragButton": "Modo Arrastrar-soltar", + "cutButton": "Cortar el área del polígono", + "deleteButton": "Borrar", + "drawCircleMarkerButton": "Crear marcador de círculo", + "rotateButton": "Rotar polígono" + }, + "map-provider-settings": "Ajustes proveedor de mapas", + "map-provider": "Proveedor de mapas", + "map-provider-google": "Google maps", + "map-provider-openstreet": "OpenStreet maps", + "map-provider-here": "HERE maps", + "map-provider-image": "Mapa de imagen", + "map-provider-tencent": "Tencent maps", + "openstreet-provider": "Proveedor OpenStreet map", + "openstreet-provider-mapnik": "OpenStreetMap.Mapnik (Default)", + "openstreet-provider-hot": "OpenStreetMap.HOT", + "openstreet-provider-esri-street": "Esri.WorldStreetMap", + "openstreet-provider-esri-topo": "Esri.WorldTopoMap", + "openstreet-provider-cartodb-positron": "CartoDB.Positron", + "openstreet-provider-cartodb-dark-matter": "CartoDB.DarkMatter", + "use-custom-provider": "Usar proveedor personalizado", + "custom-provider-tile-url": "URL de proveedor personalizado", + "google-maps-api-key": "API Key Google Maps", + "default-map-type": "Tipo de mapa por defecto", + "google-map-type-roadmap": "Carretera", + "google-map-type-satelite": "Satelite", + "google-map-type-hybrid": "Híbrido", + "google-map-type-terrain": "Terreno", + "map-layer": "Capa de mapa", + "here-map-normal-day": "HERE.normalDay (Defecto)", + "here-map-normal-night": "HERE.normalNight", + "here-map-hybrid-day": "HERE.hybridDay", + "here-map-terrain-day": "HERE.terrainDay", + "credentials": "Credenciales", + "here-app-id": "HERE app id", + "here-app-code": "HERE app code", + "tencent-maps-api-key": "API Key Tencent Maps", + "tencent-map-type-roadmap": "Carretera", + "tencent-map-type-satelite": "Satelite", + "tencent-map-type-hybrid": "Híbrido", + "image-map-background": "Fondo de mapa de imagen", + "image-map-background-from-entity-attribute": "Obtener imagen de fondo desde un atributo de la entidad", + "image-url-source-entity-alias": "Alias de entidad para URL de imagen", + "image-url-source-entity-attribute": "Atributo de entidad para URL de imagen", + "common-map-settings": "Ajustes comunes de mapas", + "x-pos-key-name": "Clave para posición X", + "y-pos-key-name": "Clave para posición Y", + "latitude-key-name": "Clave para latitud", + "longitude-key-name": "Clave para longitud", + "default-map-zoom-level": "Nivel de zoom por defecto (0 - 20)", + "default-map-center-position": "Posición central del mapa por defecto (0,0)", + "disable-scroll-zooming": "Desactivar zoom en scroll", + "disable-zoom-control-buttons": "Desactivar botones de zoom", + "fit-map-bounds": "Ajustar los límites del mapa para cubrir todos los marcadores", + "use-default-map-center-position": "Usar posición central por defecto", + "entities-limit": "Límite de entidades a cargar", + "markers-settings": "Ajustes de los marcadores", + "marker-offset-x": "Offset X relativo a la posición multiplicado por el ancho del marcador", + "marker-offset-y": "Offset Y relativo a la posición multiplicado por el alto del marcador", + "position-function": "Función de conversión de posición, debe retornar coordenadas x,y como valor double de 0 a 1", + "draggable-marker": "Marcador arrastrable", + "label": "Etiqueta", + "show-label": "Mostrar etiqueta", + "use-label-function": "Usar función de etiqueta", + "label-pattern": "Etiqueta (Ejemplos de patrón: '${entityName}', '${entityName}: (Texto ${keyName} unidades.)' )", + "label-function": "Función de etiqueta", + "tooltip": "Sugerencias (tooltip)", + "show-tooltip": "Mostrar sugerencias", + "show-tooltip-action": "Acción para mostrar las sugerencias", + "show-tooltip-action-click": "Mostrar sugerencias tooltip en click (por defecto)", + "show-tooltip-action-hover": "Mostrar sugerencias on hover", + "auto-close-tooltips": "Auto-cerrar sugerencias", + "use-tooltip-function": "Función de sugerencias", + "tooltip-pattern": "Sugerencia (Por ej. 'Texto ${keyName} unidades.' o Texto Link')", + "tooltip-function": "Función de sugerencia", + "tooltip-offset-x": "Offset X relativo al ancla del marcador multiplicado por el ancho", + "tooltip-offset-y": "Offset Y relativo al ancla del marcador multiplicado por la altura", + "color": "Color", + "use-color-function": "Usar función de color", + "color-function": "Función de color", + "marker-image": "Imagen de marcador", + "use-marker-image-function": "Usar función de imagen de marcador", + "custom-marker-image": "Imagen de marcador personalizada", + "custom-marker-image-size": "Tamaño de imagen personalizada (px)", + "marker-image-function": "Función de imagen de marcador", + "marker-images": "Imagenes de marcador", + "polygon-settings": "Ajustes de polígono", + "show-polygon": "Mostrar polígono", + "polygon-key-name": "Clave del polígono", + "enable-polygon-edit": "Polígono editable", + "polygon-label": "Etiqueta del polígono", + "show-polygon-label": "Mostrar etiqueta del polígono", + "use-polygon-label-function": "Usar funciones de etiqueta en el polígono", + "polygon-label-pattern": "Etiqueta del polígono (Ejemplos de patrón: '${entityName}', '${entityName}: (Texto ${keyName} unidades.)' )", + "polygon-label-function": "Función de etiqueta del polígono", + "polygon-tooltip": "Sugerencia polígono", + "show-polygon-tooltip": "Mostrar sugerencias", + "auto-close-polygon-tooltips": "Auto-cerrar sugerencias polígono", + "use-polygon-tooltip-function": "Usar función de sugerencias en el polígono", + "polygon-tooltip-pattern": "Sugerencias (por ej. 'Texto ${keyName} unidades.' o Texto Link')", + "polygon-tooltip-function": "Función de sugerencia de polígono", + "polygon-color": "Color de polígono", + "polygon-opacity": "Opacidad de polígono", + "use-polygon-color-function": "Usar función de color en polígono", + "polygon-color-function": "Función de color de polígono", + "polygon-stroke": "Trazo de polígono", + "stroke-color": "Color de trazo", + "stroke-opacity": "Opacidad de trazo", + "stroke-weight": "Peso de trazo", + "use-polygon-stroke-color-function": "Usar función de color de trazo en polígono", + "polygon-stroke-color-function": "Función de color de trazo", + "circle-settings": "Ajustes de círculo", + "show-circle": "Mostrar círculo", + "circle-key-name": "Clave de círculo", + "enable-circle-edit": "Activar edición de círculo", + "circle-label": "Etiqueta de círculo", + "show-circle-label": "Mostrar etiqueta de círculo", + "use-circle-label-function": "Usar función para etiqueta de círculo", + "circle-label-pattern": "Etiqueta de círculo (Ejemplos patrón: '${entityName}', '${entityName}: (Texto ${keyName} unidades.)' )", + "circle-label-function": "Funcion de etiqueta de círculo", + "circle-tooltip": "Sugerencias de círculo", + "show-circle-tooltip": "Mostrar sugerencias de círculo", + "auto-close-circle-tooltips": "Auto-cerrar sugerencias", + "use-circle-tooltip-function": "Usar función de sugerencias en círculo", + "circle-tooltip-pattern": "Sugerencia (por ej. 'Texto ${keyName} unidades.' o Texto Link')", + "circle-tooltip-function": "Función de sugerencia círculo", + "circle-fill-color": "Color de relleno círculo", + "circle-fill-color-opacity": "Opacidad color de relleno", + "use-circle-fill-color-function": "Usar función de color de relleno", + "circle-fill-color-function": "Función de color de relleno", + "circle-stroke": "Trazo del círculo", + "use-circle-stroke-color-function": "Usar función de color de trazo", + "circle-stroke-color-function": "Función de color de trazo", + "markers-clustering-settings": "Ajustes de agrupación de marcadores", + "use-map-markers-clustering": "Usar agrupación de marcadores en mapa", + "zoom-on-cluster-click": "Zoom cuando se haga click en un grupo", + "max-cluster-zoom": "Nivel máximo de zoom en la que un marcador puede ser parte de un grupo (0 - 18)", + "max-cluster-radius-pixels": "Radio máximo que un grupo cubre en píxeles", + "cluster-zoom-animation": "Mostrar animacion en marcadores cuando se haga zoom", + "show-markers-bounds-on-cluster-mouse-over": "Mostrar los limites de los marcadores cuando el raton pase por encima de un grupo", + "spiderfy-max-zoom-level": "Spiderfy al máximo nivel de zoom (para ver todos los marcadores)", + "load-optimization": "Optimización de carga", + "cluster-chunked-loading": "Usar fragmentos para añadir marcadores para que la página no se congele", + "cluster-markers-lazy-load": "Usar lazy load al añadir marcadores", + "editor-settings": "Ajustes del editor", + "enable-snapping": "Habilitar ajuste a otros vértices para dibujar con precisión", + "init-draggable-mode": "Inicializar mapa en modo arrastre", + "hide-all-edit-buttons": "Ocultar todos los botones de edición", + "hide-draw-buttons": "Ocultar botones de dibujo", + "hide-edit-buttons": "Ocultar botones de edición", + "hide-remove-button": "Ocultar botones de borrado", + "route-map-settings": "Ajustes de mapa de ruta", + "trip-animation-settings": "Ajustes de animación de ruta", + "normalization-step": "Pasos de normalización (ms)", + "tooltip-background-color": "Color de fondo de la sugerencia", + "tooltip-font-color": "Color de fuente de las sugerencias", + "tooltip-opacity": "Opacidad de las sugerencias (0-1)", + "auto-close-tooltip": "Auto-cerrar sugerencias", + "rotation-angle": "Ángulo de rotación adicional para el marcador (grados)", + "path-settings": "Ajustes de ruta", + "path-color": "Color de ruta", + "use-path-color-function": "Usar función de color de ruta", + "path-color-function": "Función de color de ruta", + "path-decorator": "Decorador de ruta", + "use-path-decorator": "Usar decorador de ruta", + "decorator-symbol": "Símbolo del decorador", + "decorator-symbol-arrow-head": "Flecha", + "decorator-symbol-dash": "Estrella", + "decorator-symbol-size": "Tamaño del decorador (px)", + "use-path-decorator-custom-color": "Usar color personalizado en el decorador", + "decorator-custom-color": "Color personalizado del decorador", + "decorator-offset": "Offset decorador", + "end-decorator-offset": "Offset final del decorador", + "decorator-repeat": "Repetición del decorador", + "points-settings": "Ajustes de puntos", + "show-points": "Mostrar puntos", + "point-color": "Color de puntos", + "point-size": "Tamaño de puntos (px)", + "use-point-color-function": "Usar función de color de puntos", + "point-color-function": "Función de color de puntos", + "use-point-as-anchor": "Usar punto como ancla", + "point-as-anchor-function": "Función de punto como ancla", + "independent-point-tooltip": "Sugerencia independiente en punto" + }, + "markdown": { + "use-markdown-text-function": "Usar función markdown/HTML", + "markdown-text-function": "Función de valor Markdown/HTML", + "markdown-text-pattern": "Patrón de Markdown/HTML (markdown o HTML con variables, por ej. '${entityName} o ${keyName} - texto.')", + "markdown-css": "Markdown/HTML CSS" + }, + "simple-card": { + "label-position": "Posición etiqueta", + "label-position-left": "Izquierda", + "label-position-top": "Superior" + }, + "table": { + "common-table-settings": "Ajustes comunes en tablas", + "enable-search": "Activar búsqueda", + "enable-sticky-header": "Mostrar siempre el encabezado", + "enable-sticky-action": "Mostrar siempre la columna de acciones", + "hidden-cell-button-display-mode": "Visualización de botones de acción oculta", + "show-empty-space-hidden-action": "Mostrar espacio vacío en lugar de celda oculta", + "dont-reserve-space-hidden-action": "No reservar espacio para los botones en celda oculta", + "display-timestamp": "Mostrar columna timestamp", + "display-milliseconds": "Mostrar milisegundos", + "display-pagination": "Mostrar páginas", + "default-page-size": "Tamaño de página por defecto", + "use-entity-label-tab-name": "Usar etiqueta de entidad en el nombre de la tabla", + "hide-empty-lines": "Ocultar líneas vacías", + "row-style": "Estilo de fila", + "use-row-style-function": "Usar función de estilo de fila", + "row-style-function": "Función de estilo de fila", + "cell-style": "Estilo de celda", + "use-cell-style-function": "Usar función de estilo de celda", + "cell-style-function": "Función de estilo de celda", + "cell-content": "Contenido de celda", + "use-cell-content-function": "Usar función de contenido de celda", + "cell-content-function": "Función de contenido de celda", + "show-latest-data-column": "Mostrar columna de últimos datos", + "latest-data-column-order": "Órden de columna de últimos datos", + "entities-table-title": "Título de tabla de entidades", + "enable-select-column-display": "Activar posibilidad de seleccionar columnas a mostrar", + "display-entity-name": "Mostrar columna de nombre de entidad", + "entity-name-column-title": "Título de columna en nombre de entidad", + "display-entity-label": "Mostrar columna de etiqueta de entidad", + "entity-label-column-title": "Título de columna en etiqueta de entidad", + "display-entity-type": "Mostrar columna de tipo de entidad", + "default-sort-order": "Ordenación por defecto", + "column-width": "Ancho de columna (px o %)", + "default-column-visibility": "Visibilidad por defecto en columna", + "column-visibility-visible": "Visible", + "column-visibility-hidden": "Oculta", + "column-selection-to-display": "Selección de columnas en 'Columnas a Mostrar'", + "column-selection-to-display-enabled": "Activada", + "column-selection-to-display-disabled": "Desactivada", + "alarms-table-title": "Título de tabla de alarmas", + "enable-alarms-selection": "Activar selección de alarmas", + "enable-alarms-search": "Activar búsqueda de alarmas", + "enable-alarm-filter": "Activar filtro de alarmas", + "display-alarm-details": "Mostrar detalles de alarma", + "allow-alarms-ack": "Permitir reconocimiento de alarmas", + "allow-alarms-clear": "Permitir borrado de alarmas" + }, + "value-source": { + "value-source": "Origen valor", + "predefined-value": "Valor predefinido", + "entity-attribute": "Valor tomado de un atributo de entidad", + "value": "Valor", + "source-entity-alias": "Alias entidad de origen", + "source-entity-attribute": "Atributo entidad de origen" + }, + "widget-font": { + "font-family": "Familia (font family)", + "size": "Tamaño", + "relative-font-size": "Tamaño fuente relativo (porcentaje)", + "font-style": "Estilo", + "font-style-normal": "Normal", + "font-style-italic": "Cursiva", + "font-style-oblique": "Subrayada", + "font-weight": "Peso", + "font-weight-normal": "Normal", + "font-weight-bold": "Negrita", + "font-weight-bolder": "Negrita+", + "font-weight-lighter": "Lighter", + "color": "Color", + "shadow-color": "Color sombra" } }, "icon": { @@ -2664,6 +4437,7 @@ "row-click": "En click de fila", "polygon-click": "Clic en polígono", "marker-click": "En click de marcador", + "circle-click": "En click de círculo", "tooltip-tag-action": "Acción de la etiqueta Tooltip", "node-selected": "Clic en el nodo seleccionado", "element-click": "Clic en el elemento HTML", @@ -2672,6 +4446,6 @@ } }, "language": { - "language": "Lenguaje" + "language": "Idioma" } } diff --git a/ui-ngx/src/assets/locale/locale.constant-it_IT.json b/ui-ngx/src/assets/locale/locale.constant-it_IT.json index 8d86e38132..52485e3722 100644 --- a/ui-ngx/src/assets/locale/locale.constant-it_IT.json +++ b/ui-ngx/src/assets/locale/locale.constant-it_IT.json @@ -123,10 +123,10 @@ "UNACK": "Non riconosciuto" }, "display-status": { - "ACTIVE_UNACK": "Active Unacknowledged", - "ACTIVE_ACK": "Active Acknowledged", - "CLEARED_UNACK": "Cleared Unacknowledged", - "CLEARED_ACK": "Cleared Acknowledged" + "ACTIVE_UNACK": "Attivo Non riconosciuto", + "ACTIVE_ACK": "Attivo Riconosciuto", + "CLEARED_UNACK": "Cancellato Non riconosciuto", + "CLEARED_ACK": "Cancellato Riconosciuto" }, "no-alarms-prompt": "Nessun allarme trovato", "created-time": "Orario di creazione", @@ -1066,9 +1066,9 @@ "modbus-register-address": "Indirizzo registro", "modbus-register-address-range": "Indirizzo registro deve essere compreso tra 0 e 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-bit-index-range": "Bit index deve essere compreso tra 0 e 15.", "modbus-register-count": "Register count", - "modbus-register-count-range": "Register count should be a positive value.", + "modbus-register-count-range": "Register count dovrebbe essereun valore positivo.", "modbus-byte-order": "Byte order", "sync": { "status": "Stato", @@ -1307,13 +1307,13 @@ "type-enrichment": "Enrichment", "type-enrichment-details": "Aggiungi informazioni addizionali nei metadati del messaggio", "type-transformation": "Trasformazione", - "type-transformation-details": "Change Message payload and Metadata", + "type-transformation-details": "Modifica payload messaggio e metadati", "type-action": "Azioni", "type-action-details": "Perform special action", "type-external": "External", "type-external-details": "Interagisci con un sistema esterno", "type-rule-chain": "Rule Chain", - "type-rule-chain-details": "Forwards incoming messages to specified Rule Chain", + "type-rule-chain-details": "Inoltra i messaggi in arrivo ad una specifica Rule Chain", "type-input": "Input", "type-input-details": "Logical input of Rule Chain, forwards incoming messages to next related Rule Node", "type-unknown": "Sconosciuto", @@ -1502,7 +1502,7 @@ "widget-action": { "header-button": "Widget header button", "open-dashboard-state": "Navigate to new dashboard state", - "update-dashboard-state": "Update current dashboard state", + "update-dashboard-state": "Aggiorna lo stato della dashboard attuale", "open-dashboard": "Navigate to other dashboard", "custom": "Custom action", "target-dashboard-state": "Target dashboard state", diff --git a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json index 11e34c9102..6d8aa21ca1 100644 --- a/ui-ngx/src/assets/locale/locale.constant-zh_CN.json +++ b/ui-ngx/src/assets/locale/locale.constant-zh_CN.json @@ -312,6 +312,11 @@ "filter-type-device-type": "设备类型", "filter-type-device-type-and-name-description": "类型为 '{{deviceType}}' 且以 '{{prefix}}' 开头的设备", "filter-type-device-type-description": "类型为 '{{deviceType}}' 的设备", + "filter-type-edge-type": "边缘类型", + "filter-type-edge-type-description": "类型为 '{{edgeType}}' 的边缘", + "filter-type-edge-type-and-name-description": "类型为 '{{edgeType}}' 且以 '{{prefix}}' 开头的边缘", + "filter-type-edge-search-query": "边缘搜索查询", + "filter-type-edge-search-query-description": "类型为 {{edgeTypes}} 且具有 {{relationType}} 关联 {{direction}} {{rootEntity}} 的边缘", "filter-type-entity-list": "实体列表", "filter-type-entity-name": "实体名称", "filter-type-entity-view-search-query": "实体视图搜索查询", @@ -409,6 +414,8 @@ "assets": "资产", "assign-asset-to-customer": "将资产分配给客户", "assign-asset-to-customer-text": "请选择要分配给客户的资产", + "assign-asset-to-edge-text": "请选择要分配给边缘的资产", + "assign-asset-to-edge-title": "将资产分配给边缘", "assign-assets": "分配资产", "assign-assets-text": "分配 { count, plural, 1 {# 个资产} other {# 个资产} } 给客户", "assign-new-asset": "分配新资产", @@ -451,6 +458,9 @@ "type": "类型", "type-required": "类型必填。", "unassign-asset": "未分配资产", + "unassign-asset-from-edge": "取消分配边缘", + "unassign-asset-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", + "unassign-asset-from-edge-title": "您确定要取消对'{{assetName}}'资产的分配吗?", "unassign-asset-text": "确认后,资产将未分配,客户无法访问。", "unassign-asset-title": "您确定要取消对'{{assetName}}'资产的分配吗?", "unassign-assets": "取消分配资产", @@ -458,6 +468,9 @@ "unassign-assets-text": "确认后,所有选定的资产将被分配,客户无法访问。", "unassign-assets-title": "您确定要取消分配 { count, plural, 1 {# 个资产} other {# 个资产} }吗?", "unassign-from-customer": "取消分配客户", + "unassign-assets-from-edge": "取消分配边缘", + "unassign-assets-from-edge-text": "确认后,所有选定的资产将被分配,边缘无法访问。", + "unassign-assets-from-edge-title": "您确定要取消分配 { count, plural, 1 {1 资产} other {# 个资产} }吗?", "view-assets": "查看资产" }, "attribute": { @@ -512,6 +525,7 @@ "type-alarm-clear": "已清除", "type-assigned-from-tenant": "从租户分配", "type-assigned-to-customer": "分配给客户", + "type-assigned-to-edge": "分配给边缘", "type-assigned-to-tenant": "分配给租户", "type-attributes-deleted": "删除属性", "type-attributes-read": "读取属性", @@ -532,6 +546,7 @@ "type-timeseries-deleted": "遥测数据已删除", "type-timeseries-updated": "遥测数据已更新", "type-unassigned-from-customer": "未分配给客户", + "type-unassigned-from-edge": "未分配给边缘", "type-updated": "更新", "user": "用户" }, @@ -603,6 +618,7 @@ "description": "说明", "details": "详情", "devices": "客户设备", + "edges": "客户边缘实例", "entity-views": "客户实体视图", "events": "事件", "idCopiedMessage": "客户ID已复制到粘贴板", @@ -610,12 +626,15 @@ "manage-customer-assets": "管理客户资产", "manage-customer-dashboards": "管理客户仪表板", "manage-customer-devices": "管理客户设备", + "manage-customer-edges": "管理客户边缘", "manage-customer-users": "管理客户用户", "manage-dashboards": "管理仪表板", "manage-devices": "管理设备", + "manage-edges": "管理边缘", "manage-public-assets": "管理公共资产", "manage-public-dashboards": "管理公共仪表板", "manage-public-devices": "管理公共设备", + "manage-public-edges": "管理公共边缘", "manage-users": "管理用户", "management": "客户管理", "no-customers-matching": "没有找到匹配 '{{entity}}' 的客户。", @@ -624,6 +643,7 @@ "public-dashboards": "公共仪表板", "public-devices": "公共设备", "public-entity-views": "公共实体视图", + "public-edges": "公共边缘", "search": "查找客户", "select-customer": "选择客户", "select-default-customer": "选择默认的客户", @@ -639,6 +659,9 @@ "alias-resolution-error-title": "仪表板别名配置错误", "assign-dashboard-to-customer": "将仪表板分配给客户", "assign-dashboard-to-customer-text": "请选择要分配给客户的仪表板", + "assign-dashboard-to-edge": "将仪表板分配给边缘", + "assign-dashboard-to-edge-text": "请选择要分配给边缘的仪表板", + "assign-dashboard-to-edge-title": "将仪表板分配给边缘", "assign-dashboards": "分配仪表板", "assign-dashboards-text": "分配 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 给客户", "assign-new-dashboard": "分配新的仪表板", @@ -773,6 +796,7 @@ "title-required": "标题必填。", "toolbar-always-open": "工具栏常驻", "unassign-dashboard": "取消分配仪表板", + "unassign-dashboard-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", "unassign-dashboard-text": "确认后,面板将被取消分配,客户将无法访问。", "unassign-dashboard-title": "您确定要取消分配仪表板 '{{dashboardTitle}}'吗?", "unassign-dashboards": "取消分配仪表板", @@ -780,6 +804,8 @@ "unassign-dashboards-action-title": "取消分配此客户 { count, plural, 1 {# 个仪表板} other {# 个仪表板} }", "unassign-dashboards-text": "确认后,所有选定的仪表板将被取消分配,客户将无法访问。", "unassign-dashboards-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", + "unassign-dashboards-from-edge-text": "确认后,所有选定的仪表板将被取消分配,边缘将无法访问。", + "unassign-dashboards-from-edge-title": "确定要取消分配仪表板 { count, plural, 1 {# 个仪表板} other {# 个仪表板} } 吗?", "unassign-from-customer": "取消分配客户", "unassign-from-customers": "客户未分配仪表板", "unassign-from-customers-text": "请选择从仪表板中取消分配的客户", @@ -1021,6 +1047,8 @@ "any-device": "任意设备", "assign-device-to-customer": "将设备分配给客户", "assign-device-to-customer-text": "请选择要分配给客户的设备", + "assign-device-to-edge-text":"请选择要分配给边缘的设备", + "assign-device-to-edge-title": "将设备分配给边缘", "assign-devices": "分配设备", "assign-devices-text": "将 {count,plural,1 {# 个设备} other {# 个设备} }分配给客户", "assign-new-device": "分配新设备", @@ -1106,8 +1134,13 @@ "unassign-device": "取消分配设备", "unassign-device-text": "确认后,设备将被取消分配,客户将无法访问。", "unassign-device-title": "您确定要取消分配设备 '{{deviceName}}'?", + "unassign-device-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", + "unassign-device-from-edge-title": "您确定要取消分配设备 '{{deviceName}}'?", "unassign-devices": "取消分配设备", "unassign-devices-action-title": "取消分配此客户 {count,plural,1 {# 个设备} other {# 个设备} }", + "unassign-devices-from-edge": "取消分配边缘", + "unassign-devices-from-edge-text": "确认后,设备将被取消分配,边缘将无法访问。", + "unassign-devices-from-edge-title": "您确定要取消分配 { count, plural, 1 {1个 设备} other {# 个设备} } 吗?", "unassign-devices-text": "确认后,所有选定的设备将被取消分配,并且客户将无法访问。", "unassign-devices-title": "确定要取消分配 {count,plural,1 {# 个设备} other {# 个设备} } 吗?", "unassign-from-customer": "取消分配客户", @@ -1133,6 +1166,133 @@ "column": "列", "row": "排" }, + "edge": { + "add": "增加边缘", + "add-edge-text": "增加新的边缘", + "any-edge": "任何边缘", + "assets": "边缘资产", + "assign-edge-to-customer": "分配边缘给客户", + "assign-edge-to-customer-text": "请选择需要分配给边缘的客户", + "assign-new-edge": "分配新边缘", + "assign-to-customer": "分配给客户", + "assign-to-customer-text": "请选择需要分配给边缘的客户", + "assigned-to-customer": "分配给: {{customerTitle}}", + "assignedToCustomer": "分配给客户", + "copy-edge-key": "复制边缘键", + "copy-edge-secret": "复制边缘密钥", + "copy-id": "复制边缘编号", + "dashboard": "边缘仪表板", + "dashboards": "边缘仪表板", + "delete": "删除边缘", + "delete-edge-text": "当心, 确认后,边缘以及所有关联数据将不可恢复。", + "delete-edge-title": "您确定删除边缘 '{{edgeName}}'?", + "delete-edges-text": "当心, 确认后,选定的边缘以及所有关联数据将不可恢复。", + "delete-edges-title": "您确认删除边缘 { count, plural, 1 {1 个边缘} other {# 个边缘} }?", + "deployed": "已部署", + "description": "描述", + "details": "详情", + "devices": "边缘设备", + "downlinks": "下行", + "edge": "边缘", + "edge-assets": "边缘资产", + "edge-dashboards": "边缘仪表板", + "edge-details": "边缘详情", + "edge-devices": "边缘设备", + "edge-entity-views": "边缘实体视图", + "edge-file": "边缘文件", + "edge-instances": "边缘实例", + "edge-key": "边缘键", + "edge-key-copied-message": "边缘键已经被复制到剪切板", + "edge-public": "边缘公开", + "edge-required": "边缘必填。", + "edge-rulechains": "边缘规则链", + "edge-secret": "边缘密钥", + "edge-secret-copied-message": "边缘密钥已经被复制到剪切板", + "edge-type": "边缘类型", + "edge-type-list-empty": "没有选择边缘类型。", + "edge-type-required": "边缘类型必填。", + "edge-types": "边缘类型", + "enter-edge-type": "输入边缘类型", + "entity-id": "实体编号", + "entity-views": "边缘实体视图", + "event-action": "事件行动", + "events": "事件", + "id-copied-message": "边缘编号已经复制到剪切板", + "import": "导入边缘", + "label": "标签", + "label-max-length": "标签长度必须少于256个字符", + "load-entity-error": "加载数据失败,实体已经被删除。", + "make-private": "私有", + "make-private-edge-text": "确认后,边缘及其所有数据将被设为私有,不被其他人访问。", + "make-private-edge-title": "您确定要将边缘 '{{edgeName}}' 设为私有?", + "make-public": "公开", + "make-public-edge-text": "确认后,边缘及其所有数据将被设为公开并可被其他人访问。", + "make-public-edge-title": "您确定要将边缘 '{{edgeName}}' 设为公开吗?", + "management": "边缘管理", + "missing-related-rule-chains-text": "分配给边缘的规则链使用规则节点将消息转发给未分配给当前边缘的规则链。

缺少的规则链列表:
{{missingRuleChains}}", + "missing-related-rule-chains-title": "边缘缺少关联规则链", + "name": "名称", + "name-max-length": "名称长度必须少于256个字符", + "name-required": "名称必填。", + "name-starts-with": "边缘名称前缀", + "no-downlinks-prompt": "没有找到下行", + "no-edge-types-matching": "没有找到匹配的边缘类型 '{{entitySubtype}}'。", + "no-edges-matching": "没有找到匹配的边缘 '{{entity}}'。", + "no-edges-text": "没有找到边缘", + "pending": "待定", + "public": "公开", + "rulechain-templates": "规则链模版", + "rulechains": "规则链", + "search": "搜索边缘", + "select-edge-type": "选择边缘类型", + "selected-edges": "{ count, plural, 1 {1 个边缘} other {# 个边缘} } 被选中", + "sync": "同步边缘", + "sync-process-started-successfully": "同步处理开始成功!", + "type-max-length": "类型长度必须少于256个字符", + "unassign-edge-text": "确定后,边缘将被取消分配,并且客户将无法访问。", + "unassign-edge-title": "您确定取消分配边缘 '{{edgeName}}'?", + "unassign-edges-text": "确定后,所有选定的边缘将被取消分配,并且客户将无法访问。", + "unassign-edges-title": "您确定要取消分配 {count,plural,1 {1 个边缘} other {# 个边缘} } 吗?", + "unassign-from-customer": "取消分配客户", + "unassign-from-edge": "取消分配边缘", + "widget-datasource-error": "组件只支持边缘实体数据源" + }, + "edge-event": { + "action-type-added": "增加", + "action-type-alarm-ack": "警告确认", + "action-type-alarm-clear": "警告清除", + "action-type-assigned-to-customer": "分配给客户", + "action-type-assigned-to-edge": "分配给边缘", + "action-type-attributes-deleted": "属性删除", + "action-type-attributes-updated": "属性更新", + "action-type-credentials-request": "认证请求", + "action-type-credentials-updated": "认证更新", + "action-type-deleted": "删除", + "action-type-entity-merge-request": "实体合并请求", + "action-type-post-attributes": "推送属性", + "action-type-relation-add-or-update": "关联增加或更新", + "action-type-relation-deleted": "关联删除", + "action-type-rpc-call": "RPC调用", + "action-type-timeseries-updated": "时序更新", + "action-type-unassigned-from-customer": "取消分配客户", + "action-type-unassigned-from-edge": "取消分配边缘", + "action-type-updated": "更新", + "type-admin-settings": "管理员设置", + "type-alarm": "告警", + "type-asset": "资产", + "type-customer": "客户", + "type-dashboard": "仪表板", + "type-device": "设备", + "type-device-profile": "设备概要", + "type-edge": "边缘", + "type-entity-view": "实体视图", + "type-relation": "关联", + "type-rule-chain": "规则链", + "type-rule-chain-metadata": "规则链元数据", + "type-user": "用户", + "type-widgets-bundle": "部件包", + "type-widgets-type": "部件类型" + }, "entity-field": { "address": "地址", "address2": "地址2", @@ -1160,6 +1320,9 @@ "any-entity-view": "任何实体视图", "assign-entity-view-to-customer": "将实体视图分配给客户", "assign-entity-view-to-customer-text": "请选择要分配给客户的实体视图", + "assign-entity-view-to-edge": "将实体视图分配给边缘", + "assign-entity-view-to-edge-text": "请选择要分配给边缘的实体视图", + "assign-entity-view-to-edge-title": "将实体视图分配给边缘", "assign-entity-views": "分配实体视图", "assign-entity-views-text": "分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} } 给客户", "assign-new-entity-view": "分配新实体视图", @@ -1244,8 +1407,14 @@ "unassign-entity-view": "未分配实体视图", "unassign-entity-view-text": "确认后,实体视图将未分配,客户无法访问。", "unassign-entity-view-title": "您确定要取消对 '{{entityViewName}}'实体视图的分配吗?", + "unassign-entity-view-from-edge": "未分配实体视图", + "unassign-entity-view-from-edge-text": "确认后,实体视图将未分配,边缘无法访问。", + "unassign-entity-view-from-edge-title": "您确定要取消对 '{{entityViewName}}'实体视图的分配吗?", "unassign-entity-views": "取消分配实体视图", "unassign-entity-views-action-title": "从客户处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", + "unassign-entity-views-from-edge-action-title": "从边缘处取消分配{count,plural,1 {# 实体视图} other {# 实体视图} }", + "unassign-entity-views-from-edge-text": "确认后,所有选定的实体视图将被分配,边缘无法访问。", + "unassign-entity-views-from-edge-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }吗?", "unassign-entity-views-text": "确认后,所有选定的实体视图将被分配,客户无法访问。", "unassign-entity-views-title": "确定要取消分配 { count, plural, 1 {# 个实体视图} other {# 个实体视图} }吗?", "unassign-from-customer": "取消分配客户", @@ -1361,7 +1530,11 @@ "unable-delete-entity-alias-text": "实体别名 '{{entityAlias}}' 被以下部件使用不能删除:
{{widgetsList}}", "unable-delete-entity-alias-title": "无法删除实体别名", "use-entity-name-filter": "用户筛选器", - "user-name-starts-with": "以 '{{prefix}}' 开头的用户" + "user-name-starts-with": "以 '{{prefix}}' 开头的用户", + "type-edge": "边缘", + "type-edges": "边缘", + "list-of-edges": "{ count, plural, 1 {1 个边缘} other {列表 # 个边缘} }", + "edge-name-starts-with": "以 '{{prefix}}' 开头的边缘" }, "error": { "unable-to-connect": "无法连接到服务器!请检查您的互联网连接。", @@ -1817,6 +1990,8 @@ "isgateway": "Is网关", "label": "标签", "name": "名称", + "routing-key": "边缘键", + "secret": "边缘密钥", "server-attribute": "服务器属性", "shared-attribute": "共享属性", "timeseries": "Timeseries", @@ -2087,6 +2262,9 @@ "rulechain": { "add": "添加规则链", "add-rulechain-text": "添加新的规则链", + "assign-to-edge": "分配规则链给边缘", + "assign-rulechain-to-edge-title": "分配规则链给边缘", + "assign-rulechain-to-edge-text": "请选择要分配给边缘的规则链", "copyId": "复制规则链ID", "create-new-rulechain": "创建新的规则链", "debug-mode": "调试模式", @@ -2098,12 +2276,15 @@ "delete-rulechains-title": "确实要删除{count, plural, 1 { 1 个规则链} other {# 个规则链} }吗?", "description": "说明", "details": "详情", + "edge-rulechain": "边缘规则链", + "edge-template-root": "根模版", "events": "事件", "export": "导出规则链", "export-failed-error": "无法导出规则链:{{error}}", "idCopiedMessage": "规则ID已经复制到粘贴板", "import": "导入规则链", "invalid-rulechain-file-error": "不能导入规则链:无效的规则链数据格式。", + "invalid-rulechain-type-error": "不能导入规则链:无效的规则链类型。期望类型为{{expectedRuleChainType}}。", "management": "规则集管理", "name": "名称", "name-required": "名称必填。", @@ -2119,10 +2300,22 @@ "search": "查找规则链", "select-rulechain": "选择规则链", "selected-rulechains": "已选择 { count, plural, 1 {# 个规则链} other {# 个规则链} }", + "set-auto-assign-to-edge": "创建时分配规则链给边缘", + "set-auto-assign-to-edge-text": "确认后,创建时规则链将自动分配给边缘。", + "set-auto-assign-to-edge-title": "您确定创建时将规则链'{{ruleChainName}}'自动分配给边缘吗", + "set-edge-template-root-rulechain": "设置规则链为边缘模版根", + "set-edge-template-root-rulechain-text": "确认后,规则链将将会成为边缘模版根,且它会成为新创建边缘的根规则链。", + "set-edge-template-root-rulechain-title": "您确定将规则链 '{{ruleChainName}}' 设置为边缘模版根吗?", "set-root": "设置为根规则链", "set-root-rulechain-text": "确认之后,规则链将变为根规格链,并将处理所有传入的传输消息。", "set-root-rulechain-title": "您确定要生成规则链'{{ruleChainName}}'根吗?", - "system": "系统" + "system": "系统", + "unassign-rulechain-from-edge-text": "确认后,规则链将会取消分配,边缘无法访问。", + "unassign-rulechains-from-edge-text": "确认后,选定的规则链将会取消分配,边缘无法访问。", + "unassign-rulechains-from-edge-title": "您确定要取消分配规则链 { count, plural, 1 {1 个规则链} other {# 个规则链} }?", + "unset-auto-assign-to-edge": "创建时分配规则链给边缘", + "unset-auto-assign-to-edge-text": "确认后,创建时规则链将不再自动分配给边缘。", + "unset-auto-assign-to-edge-title": "您确定取消创建时将规则链'{{ruleChainName}}'自动分配给边缘吗?" }, "rulenode": { "add": "添加规则节点",