From eaafdf1f874d6ad6b81257841b24f4e87d34f696 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Wed, 4 Dec 2024 17:05:37 +0100 Subject: [PATCH 001/116] implemented sending api usages in pack --- .../DefaultTbApiUsageStateService.java | 12 +++-- .../apiusage/TbApiUsageStateService.java | 4 +- .../queue/DefaultTbCoreConsumerService.java | 14 +++--- .../src/main/resources/thingsboard.yml | 2 + .../server/common/util/ProtoUtils.java | 35 +++++++++++++++ common/proto/src/main/proto/queue.proto | 22 ++++++++- .../provider/AwsSqsMonolithQueueFactory.java | 8 ++-- .../provider/AwsSqsTbCoreQueueFactory.java | 8 ++-- .../AwsSqsTbRuleEngineQueueFactory.java | 4 +- .../AwsSqsTbVersionControlQueueFactory.java | 2 +- .../provider/AwsSqsTransportQueueFactory.java | 2 +- .../InMemoryMonolithQueueFactory.java | 4 +- .../InMemoryTbTransportQueueFactory.java | 2 +- .../provider/KafkaMonolithQueueFactory.java | 12 ++--- .../provider/KafkaTbCoreQueueFactory.java | 12 ++--- .../KafkaTbRuleEngineQueueFactory.java | 6 +-- .../KafkaTbTransportQueueFactory.java | 6 +-- .../KafkaTbVersionControlQueueFactory.java | 6 +-- .../provider/PubSubMonolithQueueFactory.java | 8 ++-- .../provider/PubSubTbCoreQueueFactory.java | 8 ++-- .../PubSubTbRuleEngineQueueFactory.java | 4 +- .../PubSubTbVersionControlQueueFactory.java | 2 +- .../provider/PubSubTransportQueueFactory.java | 4 +- .../RabbitMqMonolithQueueFactory.java | 8 ++-- .../provider/RabbitMqTbCoreQueueFactory.java | 8 ++-- .../RabbitMqTbRuleEngineQueueFactory.java | 4 +- .../RabbitMqTbVersionControlQueueFactory.java | 2 +- .../RabbitMqTransportQueueFactory.java | 4 +- .../ServiceBusMonolithQueueFactory.java | 8 ++-- .../ServiceBusTbCoreQueueFactory.java | 8 ++-- .../ServiceBusTbRuleEngineQueueFactory.java | 4 +- ...erviceBusTbVersionControlQueueFactory.java | 2 +- .../ServiceBusTransportQueueFactory.java | 4 +- .../queue/provider/TbCoreQueueFactory.java | 4 +- .../provider/TbCoreQueueProducerProvider.java | 6 +-- .../provider/TbQueueProducerProvider.java | 4 +- .../TbRuleEngineProducerProvider.java | 6 +-- .../TbTransportQueueProducerProvider.java | 6 +-- .../TbUsageStatsClientQueueFactory.java | 4 +- .../TbVersionControlProducerProvider.java | 6 +-- .../DefaultTbApiUsageReportClient.java | 45 +++++++++++++++---- .../src/main/resources/tb-vc-executor.yml | 2 + .../src/main/resources/tb-coap-transport.yml | 2 + .../src/main/resources/tb-http-transport.yml | 2 + .../src/main/resources/tb-lwm2m-transport.yml | 2 + .../src/main/resources/tb-mqtt-transport.yml | 2 + .../src/main/resources/tb-snmp-transport.yml | 2 + 47 files changed, 216 insertions(+), 116 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 60bf529ace..82413013a3 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -55,11 +55,13 @@ import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.msg.tools.SchedulerUtils; +import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionService; @@ -153,9 +155,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService } @Override - public void process(TbProtoQueueMsg msg, TbCallback callback) { - ToUsageStatsServiceMsg statsMsg = msg.getValue(); + public void process(TbProtoQueueMsg msgPack, TbCallback callback) { + msgPack.getValue().getMsgsList().forEach(this::process); + callback.onSuccess(); + } + private void process(ToUsageStatsServiceMsg statsMsg) { TenantId tenantId = TenantId.fromUUID(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); EntityId ownerId; if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) { @@ -165,7 +170,6 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService } processEntityUsageStats(tenantId, ownerId, statsMsg.getValuesList(), statsMsg.getServiceId()); - callback.onSuccess(); } private void processEntityUsageStats(TenantId tenantId, EntityId ownerId, List values, String serviceId) { @@ -190,7 +194,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); Set apiFeatures = new HashSet<>(); for (UsageStatsKVProto statsItem : values) { - ApiUsageRecordKey recordKey = ApiUsageRecordKey.valueOf(statsItem.getKey()); + ApiUsageRecordKey recordKey = ProtoUtils.fromProto(statsItem.getKey()); StatsCalculationResult calculationResult = usageState.calculate(recordKey, statsItem.getValue(), serviceId); if (calculationResult.isValueChanged()) { diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java index 5b5b1b5225..27673ccc92 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java @@ -22,13 +22,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.stats.TbApiUsageStateClient; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; public interface TbApiUsageStateService extends TbApiUsageStateClient, RuleEngineApiUsageStateService, ApplicationListener { - void process(TbProtoQueueMsg msg, TbCallback callback); + void process(TbProtoQueueMsg msg, TbCallback callback); void onTenantProfileUpdate(TenantProfileId tenantProfileId); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 3aaa36b068..6d4a108107 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -74,7 +74,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdatePr import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -150,7 +150,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService, CoreQueueConfig> mainConsumer; - private QueueConsumerManager> usageStatsConsumer; + private QueueConsumerManager> usageStatsConsumer; private QueueConsumerManager> firmwareStatesConsumer; private volatile ListeningExecutorService deviceActivityEventsExecutor; @@ -207,7 +207,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService>builder() + this.usageStatsConsumer = QueueConsumerManager.>builder() .name("TB Usage Stats") .msgPackProcessor(this::processUsageStatsMsg) .pollInterval(pollInterval) @@ -402,11 +402,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> msgs, TbQueueConsumer> consumer) throws Exception { - ConcurrentMap> pendingMap = msgs.stream().collect( + private void processUsageStatsMsg(List> msgs, TbQueueConsumer> consumer) throws Exception { + ConcurrentMap> pendingMap = msgs.stream().collect( Collectors.toConcurrentMap(s -> UUID.randomUUID(), Function.identity())); CountDownLatch processingTimeoutLatch = new CountDownLatch(1); - TbPackProcessingContext> ctx = new TbPackProcessingContext<>( + TbPackProcessingContext> ctx = new TbPackProcessingContext<>( processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>()); pendingMap.forEach((id, msg) -> { log.trace("[{}] Creating usage stats callback for message: {}", id, msg.getValue()); @@ -453,7 +453,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService msg, TbCallback callback) { + private void handleUsageStats(TbProtoQueueMsg msg, TbCallback callback) { statsService.process(msg, callback); } diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index f642d7fea5..163a87046d 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -188,6 +188,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Statistics reporting interval, set to send summarized data every 10 seconds by default interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" check: # Interval of checking the start of the next cycle and re-enabling the blocked tenants/customers cycle: "${USAGE_STATS_CHECK_CYCLE:60000}" diff --git a/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java b/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java index 264b23f118..62a7d266d3 100644 --- a/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java +++ b/common/proto/src/main/java/org/thingsboard/server/common/util/ProtoUtils.java @@ -20,6 +20,7 @@ import com.fasterxml.jackson.databind.JsonNode; import com.google.protobuf.ByteString; import lombok.extern.slf4j.Slf4j; import org.thingsboard.common.util.JacksonUtil; +import org.thingsboard.server.common.data.ApiUsageRecordKey; import org.thingsboard.server.common.data.ApiUsageState; import org.thingsboard.server.common.data.ApiUsageStateValue; import org.thingsboard.server.common.data.Device; @@ -88,6 +89,7 @@ import org.thingsboard.server.common.msg.rule.engine.DeviceDeleteMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceEdgeUpdateMsg; import org.thingsboard.server.common.msg.rule.engine.DeviceNameOrTypeUpdateMsg; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ApiUsageRecordKeyProto; import java.util.ArrayList; import java.util.Arrays; @@ -399,6 +401,39 @@ public class ProtoUtils { return builder.build(); } + public static ApiUsageRecordKeyProto toProto(ApiUsageRecordKey apiUsageRecordKey) { + return switch (apiUsageRecordKey) { + case TRANSPORT_MSG_COUNT -> ApiUsageRecordKeyProto.TRANSPORT_MSG_COUNT; + case TRANSPORT_DP_COUNT -> ApiUsageRecordKeyProto.TRANSPORT_DP_COUNT; + case STORAGE_DP_COUNT -> ApiUsageRecordKeyProto.STORAGE_DP_COUNT; + case RE_EXEC_COUNT -> ApiUsageRecordKeyProto.RE_EXEC_COUNT; + case JS_EXEC_COUNT -> ApiUsageRecordKeyProto.JS_EXEC_COUNT; + case TBEL_EXEC_COUNT -> ApiUsageRecordKeyProto.TBEL_EXEC_COUNT; + case EMAIL_EXEC_COUNT -> ApiUsageRecordKeyProto.EMAIL_EXEC_COUNT; + case SMS_EXEC_COUNT -> ApiUsageRecordKeyProto.SMS_EXEC_COUNT; + case CREATED_ALARMS_COUNT -> ApiUsageRecordKeyProto.CREATED_ALARMS_COUNT; + case ACTIVE_DEVICES -> ApiUsageRecordKeyProto.ACTIVE_DEVICES; + case INACTIVE_DEVICES -> ApiUsageRecordKeyProto.INACTIVE_DEVICES; + }; + } + + public static ApiUsageRecordKey fromProto(ApiUsageRecordKeyProto proto) { + return switch (proto) { + case UNRECOGNIZED -> null; + case TRANSPORT_MSG_COUNT -> ApiUsageRecordKey.TRANSPORT_MSG_COUNT; + case TRANSPORT_DP_COUNT -> ApiUsageRecordKey.TRANSPORT_DP_COUNT; + case STORAGE_DP_COUNT -> ApiUsageRecordKey.STORAGE_DP_COUNT; + case RE_EXEC_COUNT -> ApiUsageRecordKey.RE_EXEC_COUNT; + case JS_EXEC_COUNT -> ApiUsageRecordKey.JS_EXEC_COUNT; + case TBEL_EXEC_COUNT -> ApiUsageRecordKey.TBEL_EXEC_COUNT; + case EMAIL_EXEC_COUNT -> ApiUsageRecordKey.EMAIL_EXEC_COUNT; + case SMS_EXEC_COUNT -> ApiUsageRecordKey.SMS_EXEC_COUNT; + case CREATED_ALARMS_COUNT -> ApiUsageRecordKey.CREATED_ALARMS_COUNT; + case ACTIVE_DEVICES -> ApiUsageRecordKey.ACTIVE_DEVICES; + case INACTIVE_DEVICES -> ApiUsageRecordKey.INACTIVE_DEVICES; + }; + } + private static ToDeviceActorNotificationMsg fromProto(TransportProtos.DeviceAttributesEventMsgProto proto) { return new DeviceAttributesEventNotificationMsg( TenantId.fromUUID(new UUID(proto.getTenantIdMSB(), proto.getTenantIdLSB())), diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 228a4039d2..3541654b73 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -61,6 +61,20 @@ enum EntityTypeProto { MOBILE_APP_BUNDLE = 38; } +enum ApiUsageRecordKeyProto { + TRANSPORT_MSG_COUNT = 0; + TRANSPORT_DP_COUNT = 1; + STORAGE_DP_COUNT = 2; + RE_EXEC_COUNT = 3; + JS_EXEC_COUNT = 4; + TBEL_EXEC_COUNT = 5; + EMAIL_EXEC_COUNT = 6; + SMS_EXEC_COUNT = 7; + CREATED_ALARMS_COUNT = 8; + ACTIVE_DEVICES = 9; + INACTIVE_DEVICES = 10; +} + /** * Service Discovery Data Structures; */ @@ -1588,8 +1602,8 @@ message ToTransportMsg { repeated QueueDeleteMsg queueDeleteMsgs = 16; } -message UsageStatsKVProto{ - string key = 1; +message UsageStatsKVProto { + ApiUsageRecordKeyProto key = 1; int64 value = 2; } @@ -1604,6 +1618,10 @@ message ToUsageStatsServiceMsg { string serviceId = 8; } +message ToUsageStatsServiceMsgPack { + repeated ToUsageStatsServiceMsg msgs = 1; +} + message ToOtaPackageStateServiceMsg { int64 ts = 1; int64 tenantIdMSB = 2; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java index 310cc1d1c5..8efc66f2c1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsMonolithQueueFactory.java @@ -34,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -211,14 +211,14 @@ public class AwsSqsMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java index 515c1bba44..29676deb5e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbCoreQueueFactory.java @@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -189,14 +189,14 @@ public class AwsSqsTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbAwsSqsConsumerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java index a93aba2764..31dde9228d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbRuleEngineQueueFactory.java @@ -32,7 +32,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -172,7 +172,7 @@ public class AwsSqsTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbVersionControlQueueFactory.java index 67ff0393bd..58dc8b7c88 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTbVersionControlQueueFactory.java @@ -62,7 +62,7 @@ public class AwsSqsTbVersionControlQueueFactory implements TbVersionControlQueue } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java index 407ef86a99..7c649d879a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/AwsSqsTransportQueueFactory.java @@ -126,7 +126,7 @@ public class AwsSqsTransportQueueFactory implements TbTransportQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbAwsSqsProducerTemplate<>(coreAdmin, sqsSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index d70cad159b..d4ca701b51 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -140,7 +140,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new InMemoryTbQueueConsumer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } @@ -155,7 +155,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new InMemoryTbQueueProducer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java index 4ee79aef60..2d8e124172 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java @@ -116,7 +116,7 @@ public class InMemoryTbTransportQueueFactory implements TbTransportQueueFactory } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new InMemoryTbQueueProducer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index dd5d61e834..18d1a3af00 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -35,7 +35,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -320,13 +320,13 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); consumerBuilder.clientId("monolith-us-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId(topicService.buildTopicName("monolith-us-consumer")); - consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(coreAdmin); consumerBuilder.statsService(consumerStatsService); return consumerBuilder.build(); @@ -356,8 +356,8 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("monolith-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java index cc0e044917..b6a2e252ff 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java @@ -34,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -269,13 +269,13 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); consumerBuilder.clientId("tb-core-us-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId(topicService.buildTopicName("tb-core-us-consumer")); - consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(coreAdmin); consumerBuilder.statsService(consumerStatsService); return consumerBuilder.build(); @@ -305,8 +305,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index 87a1a69c2e..68f5fee9c2 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -33,7 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -274,8 +274,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java index dd260840f5..daa78a08f6 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMs import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -165,8 +165,8 @@ public class KafkaTbTransportQueueFactory implements TbTransportQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("transport-node-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java index aacebb8579..7e6c05dcae 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java @@ -20,7 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; @@ -98,8 +98,8 @@ public class KafkaTbVersionControlQueueFactory implements TbVersionControlQueueF } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-vc-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java index 05bef819b7..d72fde8441 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubMonolithQueueFactory.java @@ -34,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -211,9 +211,9 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -228,7 +228,7 @@ public class PubSubMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEng } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java index 919d895a97..ae7c1ab7f0 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbCoreQueueFactory.java @@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -181,9 +181,9 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbPubSubConsumerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -198,7 +198,7 @@ public class PubSubTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java index 671da15f20..edf304057d 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbRuleEngineQueueFactory.java @@ -33,7 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -177,7 +177,7 @@ public class PubSubTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbVersionControlQueueFactory.java index b6da4e2973..3261ad8dfd 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTbVersionControlQueueFactory.java @@ -62,7 +62,7 @@ public class PubSubTbVersionControlQueueFactory implements TbVersionControlQueue } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java index a7500d2083..fa2f7793e7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/PubSubTransportQueueFactory.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMs import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -126,7 +126,7 @@ public class PubSubTransportQueueFactory implements TbTransportQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbPubSubProducerTemplate<>(coreAdmin, pubSubSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java index 3c59923def..e5cdeb1741 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqMonolithQueueFactory.java @@ -34,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -209,9 +209,9 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -226,7 +226,7 @@ public class RabbitMqMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java index 16f9838384..2fcd7936c1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbCoreQueueFactory.java @@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -211,9 +211,9 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbRabbitMqConsumerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -228,7 +228,7 @@ public class RabbitMqTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java index a7af729e1f..773b1644de 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbRuleEngineQueueFactory.java @@ -32,7 +32,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -170,7 +170,7 @@ public class RabbitMqTbRuleEngineQueueFactory implements TbRuleEngineQueueFactor } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbVersionControlQueueFactory.java index 604955be2c..56b1ea40f5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTbVersionControlQueueFactory.java @@ -62,7 +62,7 @@ public class RabbitMqTbVersionControlQueueFactory implements TbVersionControlQue } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java index ea922557bd..f3bc3094a4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/RabbitMqTransportQueueFactory.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMs import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -127,7 +127,7 @@ public class RabbitMqTransportQueueFactory implements TbTransportQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbRabbitMqProducerTemplate<>(coreAdmin, rabbitMqSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java index 932bbd21e5..c0e6977b35 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusMonolithQueueFactory.java @@ -33,7 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -208,9 +208,9 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -225,7 +225,7 @@ public class ServiceBusMonolithQueueFactory implements TbCoreQueueFactory, TbRul } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java index 71a7efe50b..7cc1183c80 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbCoreQueueFactory.java @@ -31,7 +31,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -181,9 +181,9 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new TbServiceBusConsumerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic()), - msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); + msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); } @Override @@ -198,7 +198,7 @@ public class ServiceBusTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java index 54661f695c..33fd286704 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbRuleEngineQueueFactory.java @@ -32,7 +32,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -170,7 +170,7 @@ public class ServiceBusTbRuleEngineQueueFactory implements TbRuleEngineQueueFact } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbVersionControlQueueFactory.java index 0c363488ce..2f02f530c1 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTbVersionControlQueueFactory.java @@ -62,7 +62,7 @@ public class ServiceBusTbVersionControlQueueFactory implements TbVersionControlQ } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java index 7f3e246eec..1481ec58ac 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/ServiceBusTransportQueueFactory.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMs import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -128,7 +128,7 @@ public class ServiceBusTransportQueueFactory implements TbTransportQueueFactory } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new TbServiceBusProducerTemplate<>(coreAdmin, serviceBusSettings, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java index c4002f4d3e..b9ccfd1866 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java @@ -28,7 +28,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -91,7 +91,7 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory, Hous * * @return */ - TbQueueConsumer> createToUsageStatsServiceMsgConsumer(); + TbQueueConsumer> createToUsageStatsServiceMsgConsumer(); /** * Used to consume messages about firmware update notifications by TB Core Service diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java index 9cf18e6cb4..386a525b28 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java @@ -26,7 +26,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -45,7 +45,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { private TbQueueProducer> toEdge; private TbQueueProducer> toEdgeNotifications; private TbQueueProducer> toEdgeEvents; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toVersionControl; private TbQueueProducer> toHousekeeper; @@ -94,7 +94,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java index ec31763baa..d5c011c7b9 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -74,7 +74,7 @@ public interface TbQueueProducerProvider { * * @return */ - TbQueueProducer> getTbUsageStatsMsgProducer(); + TbQueueProducer> getTbUsageStatsMsgProducer(); /** * Used to push messages to other instances of TB Core Service diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java index e9f7773a26..835b02ec8e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -42,7 +42,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider { private TbQueueProducer> toTbCore; private TbQueueProducer> toRuleEngineNotifications; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; private TbQueueProducer> toEdge; private TbQueueProducer> toEdgeNotifications; @@ -107,7 +107,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider { } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java index 7960cbcf32..689d236de7 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -40,7 +40,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider private TbQueueProducer> toRuleEngine; private TbQueueProducer> toTbCore; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; public TbTransportQueueProducerProvider(TbTransportQueueFactory tbQueueProvider) { @@ -102,7 +102,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java index 0c551fc998..c4c5f5215a 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java @@ -15,12 +15,12 @@ */ package org.thingsboard.server.queue.provider; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; public interface TbUsageStatsClientQueueFactory { - TbQueueProducer> createToUsageStatsServiceMsgProducer(); + TbQueueProducer> createToUsageStatsServiceMsgProducer(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java index cd4fa12df0..400ccfc085 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -38,7 +38,7 @@ public class TbVersionControlProducerProvider implements TbQueueProducerProvider private final TbVersionControlQueueFactory tbQueueProvider; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; public TbVersionControlProducerProvider(TbVersionControlQueueFactory tbQueueProvider) { @@ -98,7 +98,7 @@ public class TbVersionControlProducerProvider implements TbQueueProducerProvider } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java index e8502145ec..10ea5b13a0 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java @@ -29,7 +29,10 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.stats.TbApiUsageReportClient; +import org.thingsboard.server.common.util.ProtoUtils; +import org.thingsboard.server.gen.transport.TransportProtos; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -38,13 +41,18 @@ import org.thingsboard.server.queue.discovery.TbServiceInfoProvider; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; import org.thingsboard.server.queue.scheduler.SchedulerComponent; +import java.util.ArrayList; import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.Random; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import java.util.stream.IntStream; @Component @Slf4j @@ -57,6 +65,8 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { private boolean enabledPerCustomer; @Value("${usage.stats.report.interval:10}") private int interval; + @Value("${usage.stats.report.pack_size:1024}") + private int packSize; private final EnumMap> stats = new EnumMap<>(ApiUsageRecordKey.class); @@ -64,7 +74,7 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { private final TbServiceInfoProvider serviceInfoProvider; private final SchedulerComponent scheduler; private final TbQueueProducerProvider producerProvider; - private TbQueueProducer> msgProducer; + private TbQueueProducer> msgProducer; @PostConstruct private void init() { @@ -110,31 +120,50 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { }); UsageStatsKVProto.Builder statsItem = UsageStatsKVProto.newBuilder() - .setKey(key.name()) + .setKey(ProtoUtils.toProto(key)) .setValue(value); statsMsg.addValues(statsItem.build()); }); statsForKey.clear(); } - report.forEach(((parent, statsMsg) -> { - //TODO: figure out how to minimize messages into the queue. Maybe group by 100s of messages? + Map> reportStatsPerTpi = new HashMap<>(); + + report.forEach((parent, statsMsg) -> { try { TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_CORE, parent.getTenantId(), parent.getId()) .newByTopic(msgProducer.getDefaultTopic()); - msgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), statsMsg.build()), null); + reportStatsPerTpi.computeIfAbsent(tpi, k -> new ArrayList<>()).add(statsMsg.build()); } catch (TenantNotFoundException e) { log.debug("Couldn't report usage stats for non-existing tenant: {}", e.getTenantId()); - } catch (Exception e) { - log.warn("Failed to report usage stats for tenant {}", parent.getTenantId(), e); } - })); + }); + + reportStatsPerTpi.forEach((tpi, statsList) -> { + toMsgPack(statsList).forEach(pack -> { + try { + msgProducer.send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), pack), null); + } catch (Exception e) { + log.warn("Failed to report usage stats pack to TPI {}", tpi, e); + } + }); + }); if (!report.isEmpty()) { log.debug("Reporting API usage statistics for {} tenants and customers", report.size()); } } + private List toMsgPack(List list) { + return IntStream.range(0, (list.size() + packSize - 1) / packSize) + .mapToObj(i -> { + var packList = list.subList(i * packSize, Math.min((i + 1) * packSize, list.size())); + var pack = ToUsageStatsServiceMsgPack.newBuilder(); + pack.addAllMsgs(packList); + return pack.build(); + }).toList(); + } + @Override public void report(TenantId tenantId, CustomerId customerId, ApiUsageRecordKey key, long value) { if (!enabled) return; diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 6b79f2d101..32cdb6085f 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -289,6 +289,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 2c1c0550e1..23ddc2efc5 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -478,6 +478,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index 3c28c6ddf6..bc0cea209e 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -448,6 +448,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index bafe77ee92..c2c0bf8e93 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -548,6 +548,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 51a2c173a7..88bd34280d 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -481,6 +481,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index df222fe09f..0e587b6028 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -434,6 +434,8 @@ usage: enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + # Amount of statistic messages in pack + pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" # Metrics parameters metrics: From dcf4eb27930942412d418135565a48c70a770a33 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 10 Dec 2024 16:04:11 +0100 Subject: [PATCH 002/116] refactored due to comments --- .../DefaultTbApiUsageReportClient.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java index 10ea5b13a0..e667256e06 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java @@ -15,6 +15,7 @@ */ package org.thingsboard.server.queue.usagestats; +import com.google.common.collect.Lists; import jakarta.annotation.PostConstruct; import lombok.Data; import lombok.RequiredArgsConstructor; @@ -52,7 +53,6 @@ import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; -import java.util.stream.IntStream; @Component @Slf4j @@ -155,13 +155,13 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { } private List toMsgPack(List list) { - return IntStream.range(0, (list.size() + packSize - 1) / packSize) - .mapToObj(i -> { - var packList = list.subList(i * packSize, Math.min((i + 1) * packSize, list.size())); - var pack = ToUsageStatsServiceMsgPack.newBuilder(); - pack.addAllMsgs(packList); - return pack.build(); - }).toList(); + return Lists.partition(list, packSize) + .stream() + .map(partition -> + ToUsageStatsServiceMsgPack.newBuilder() + .addAllMsgs(partition) + .build()) + .toList(); } @Override From b848df943bbaa26e018b9a8d8d6e73cd4252ef64 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 13 Jan 2025 19:24:37 +0100 Subject: [PATCH 003/116] set default usage.stats.report.interval to 60 sec --- application/src/main/resources/thingsboard.yml | 2 +- msa/vc-executor/src/main/resources/tb-vc-executor.yml | 2 +- transport/coap/src/main/resources/tb-coap-transport.yml | 2 +- transport/http/src/main/resources/tb-http-transport.yml | 2 +- transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml | 2 +- transport/mqtt/src/main/resources/tb-mqtt-transport.yml | 2 +- transport/snmp/src/main/resources/tb-snmp-transport.yml | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/application/src/main/resources/thingsboard.yml b/application/src/main/resources/thingsboard.yml index 163a87046d..bcb0517df0 100644 --- a/application/src/main/resources/thingsboard.yml +++ b/application/src/main/resources/thingsboard.yml @@ -187,7 +187,7 @@ usage: # Enable/Disable the collection of API usage statistics on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Statistics reporting interval, set to send summarized data every 10 seconds by default - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" check: diff --git a/msa/vc-executor/src/main/resources/tb-vc-executor.yml b/msa/vc-executor/src/main/resources/tb-vc-executor.yml index 32cdb6085f..f2ff04fddd 100644 --- a/msa/vc-executor/src/main/resources/tb-vc-executor.yml +++ b/msa/vc-executor/src/main/resources/tb-vc-executor.yml @@ -288,7 +288,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" diff --git a/transport/coap/src/main/resources/tb-coap-transport.yml b/transport/coap/src/main/resources/tb-coap-transport.yml index 23ddc2efc5..7e998eb0c4 100644 --- a/transport/coap/src/main/resources/tb-coap-transport.yml +++ b/transport/coap/src/main/resources/tb-coap-transport.yml @@ -477,7 +477,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" diff --git a/transport/http/src/main/resources/tb-http-transport.yml b/transport/http/src/main/resources/tb-http-transport.yml index bc0cea209e..d8c157e091 100644 --- a/transport/http/src/main/resources/tb-http-transport.yml +++ b/transport/http/src/main/resources/tb-http-transport.yml @@ -447,7 +447,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" diff --git a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml index c2c0bf8e93..11dd4f1251 100644 --- a/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml +++ b/transport/lwm2m/src/main/resources/tb-lwm2m-transport.yml @@ -547,7 +547,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" diff --git a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml index 88bd34280d..f2ce184b66 100644 --- a/transport/mqtt/src/main/resources/tb-mqtt-transport.yml +++ b/transport/mqtt/src/main/resources/tb-mqtt-transport.yml @@ -480,7 +480,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" diff --git a/transport/snmp/src/main/resources/tb-snmp-transport.yml b/transport/snmp/src/main/resources/tb-snmp-transport.yml index 0e587b6028..08bf7dbb54 100644 --- a/transport/snmp/src/main/resources/tb-snmp-transport.yml +++ b/transport/snmp/src/main/resources/tb-snmp-transport.yml @@ -433,7 +433,7 @@ usage: # Enable/Disable collection of statistics about API usage on a customer level enabled_per_customer: "${USAGE_STATS_REPORT_PER_CUSTOMER_ENABLED:false}" # Interval of reporting the statistics. By default, the summarized statistics are sent every 10 seconds - interval: "${USAGE_STATS_REPORT_INTERVAL:10}" + interval: "${USAGE_STATS_REPORT_INTERVAL:60}" # Amount of statistic messages in pack pack_size: "${USAGE_STATS_REPORT_PACK_SIZE:1024}" From 933d1447d2cef1f0c82c90a3e19c942d43c59543 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 14 Jan 2025 12:08:53 +0100 Subject: [PATCH 004/116] refactoring due to comments (removed serviceId duplications in ToUsageStatsServiceMsgPack) --- .../service/apiusage/DefaultTbApiUsageStateService.java | 7 ++++--- common/proto/src/main/proto/queue.proto | 2 +- .../queue/usagestats/DefaultTbApiUsageReportClient.java | 3 +-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 803d85b57a..0cc02e5cf4 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -157,11 +157,12 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService @Override public void process(TbProtoQueueMsg msgPack, TbCallback callback) { - msgPack.getValue().getMsgsList().forEach(this::process); + String serviceId = msgPack.getValue().getServiceId(); + msgPack.getValue().getMsgsList().forEach(msg -> process(msg, serviceId)); callback.onSuccess(); } - private void process(ToUsageStatsServiceMsg statsMsg) { + private void process(ToUsageStatsServiceMsg statsMsg, String serviceId) { TenantId tenantId = TenantId.fromUUID(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); EntityId ownerId; if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) { @@ -170,7 +171,7 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService ownerId = tenantId; } - processEntityUsageStats(tenantId, ownerId, statsMsg.getValuesList(), statsMsg.getServiceId()); + processEntityUsageStats(tenantId, ownerId, statsMsg.getValuesList(), serviceId); } private void processEntityUsageStats(TenantId tenantId, EntityId ownerId, List values, String serviceId) { diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 3541654b73..0e318c3b30 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -1615,11 +1615,11 @@ message ToUsageStatsServiceMsg { repeated UsageStatsKVProto values = 5; int64 customerIdMSB = 6; int64 customerIdLSB = 7; - string serviceId = 8; } message ToUsageStatsServiceMsgPack { repeated ToUsageStatsServiceMsg msgs = 1; + string serviceId = 2; } message ToOtaPackageStateServiceMsg { diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java index e667256e06..8c0439362b 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java @@ -115,7 +115,6 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { newStatsMsg.setCustomerIdLSB(customerId.getId().getLeastSignificantBits()); } - newStatsMsg.setServiceId(serviceInfoProvider.getServiceId()); return newStatsMsg; }); @@ -124,7 +123,6 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { .setValue(value); statsMsg.addValues(statsItem.build()); }); - statsForKey.clear(); } Map> reportStatsPerTpi = new HashMap<>(); @@ -160,6 +158,7 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { .map(partition -> ToUsageStatsServiceMsgPack.newBuilder() .addAllMsgs(partition) + .setServiceId(serviceInfoProvider.getServiceId()) .build()) .toList(); } From 89900a6deeb39eabbf6cabcf54497eae729bf2a0 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Tue, 14 Jan 2025 13:53:48 +0100 Subject: [PATCH 005/116] minor refactoring due to better merge with pe --- .../DefaultTbApiUsageStateService.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index 0cc02e5cf4..af4da51a45 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -61,7 +61,6 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -158,20 +157,18 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService @Override public void process(TbProtoQueueMsg msgPack, TbCallback callback) { String serviceId = msgPack.getValue().getServiceId(); - msgPack.getValue().getMsgsList().forEach(msg -> process(msg, serviceId)); - callback.onSuccess(); - } - - private void process(ToUsageStatsServiceMsg statsMsg, String serviceId) { - TenantId tenantId = TenantId.fromUUID(new UUID(statsMsg.getTenantIdMSB(), statsMsg.getTenantIdLSB())); - EntityId ownerId; - if (statsMsg.getCustomerIdMSB() != 0 && statsMsg.getCustomerIdLSB() != 0) { - ownerId = new CustomerId(new UUID(statsMsg.getCustomerIdMSB(), statsMsg.getCustomerIdLSB())); - } else { - ownerId = tenantId; - } + msgPack.getValue().getMsgsList().forEach(msg -> { + TenantId tenantId = TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); + EntityId ownerId; + if (msg.getCustomerIdMSB() != 0 && msg.getCustomerIdLSB() != 0) { + ownerId = new CustomerId(new UUID(msg.getCustomerIdMSB(), msg.getCustomerIdLSB())); + } else { + ownerId = tenantId; + } - processEntityUsageStats(tenantId, ownerId, statsMsg.getValuesList(), serviceId); + processEntityUsageStats(tenantId, ownerId, msg.getValuesList(), serviceId); + }); + callback.onSuccess(); } private void processEntityUsageStats(TenantId tenantId, EntityId ownerId, List values, String serviceId) { From 64f15f99df3712ff8b73f008f6bde0f902329da2 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 16 Jan 2025 16:00:17 +0200 Subject: [PATCH 006/116] Added provisioning device mobile action --- .../mobile-action-editor.component.html | 30 +++++++++++++++ .../action/mobile-action-editor.component.ts | 26 ++++++++++++- .../action/mobile-action-editor.models.ts | 17 +++++++++ .../components/widget/widget.component.ts | 20 ++++++++++ ui-ngx/src/app/shared/models/widget.models.ts | 37 +++++++++++++++++-- .../assets/locale/locale.constant-en_US.json | 10 +++++ 6 files changed, 134 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html index fb1afd544d..1e5c3cadd5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html @@ -36,6 +36,36 @@ + +
+
{{ 'widget-action.mobile.provisioning-device.type' | translate }}*
+ + + + {{ widgetMobileProvisionTypeTranslationMap.get(mobileProvisionType[actionType]) | translate }} + + + + warning + + +
+ +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts index e949f765c6..593cedbb27 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.ts @@ -24,10 +24,12 @@ import { } from '@angular/forms'; import { coerceBooleanProperty } from '@angular/cdk/coercion'; import { + WidgetMobileProvisionType, WidgetActionType, WidgetMobileActionDescriptor, WidgetMobileActionType, - widgetMobileActionTypeTranslationMap + widgetMobileActionTypeTranslationMap, + widgetMobileProvisionTypeTranslationMap } from '@shared/models/widget.models'; import { CustomActionEditorCompleter } from '@home/components/widget/lib/settings/common/action/custom-action.models'; import { @@ -38,7 +40,8 @@ import { getDefaultProcessImageFunction, getDefaultProcessLaunchResultFunction, getDefaultProcessLocationFunction, - getDefaultProcessQrCodeFunction + getDefaultProcessQrCodeFunction, + getDefaultProvisioningSuccessFunction } from '@home/components/widget/lib/settings/common/action/mobile-action-editor.models'; import { WidgetService } from '@core/http/widget.service'; import { TbFunction } from '@shared/models/js-function.models'; @@ -59,6 +62,9 @@ export class MobileActionEditorComponent implements ControlValueAccessor, OnInit mobileActionTypes = Object.keys(WidgetMobileActionType); mobileActionTypeTranslations = widgetMobileActionTypeTranslationMap; mobileActionType = WidgetMobileActionType; + mobileProvisionType = WidgetMobileProvisionType; + mobileProvisionTypes = Object.keys(WidgetMobileProvisionType); + widgetMobileProvisionTypeTranslationMap = widgetMobileProvisionTypeTranslationMap; customActionEditorCompleter = CustomActionEditorCompleter; @@ -254,6 +260,22 @@ export class MobileActionEditorComponent implements ControlValueAccessor, OnInit this.fb.control(processLocationFunction, [Validators.required]) ); break; + case WidgetMobileActionType.provisioningDevice: + let handleProvisionSuccessFunction = action?.handleProvisionSuccessFunction; + if (changed) { + const defaultProvisioningSuccessFunction = getDefaultProvisioningSuccessFunction(); + if (defaultProvisioningSuccessFunction !== handleProvisionSuccessFunction) { + handleProvisionSuccessFunction = defaultProvisioningSuccessFunction; + } + } + this.mobileActionTypeFormGroup.addControl( + 'handleProvisionSuccessFunction', + this.fb.control(handleProvisionSuccessFunction, [Validators.required]) + ); + this.mobileActionTypeFormGroup.addControl( + 'provisionType', + this.fb.control(null, [Validators.required]) + ); } } this.mobileActionTypeFormGroup.valueChanges.pipe( diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts index 830a907a09..8366334f2c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts @@ -138,6 +138,15 @@ const processLocationFunction: TbFunction = ' }, 100);\n' + '}'; +const provisioningSuccessFunction: TbFunction = + '// Function body to handle device provision success. \n' + + '// - device - device that was successfully provisioned.\n' + + 'function showDeviceProvisioningSuccess(deviceName, message) {\n' + + ' setTimeout(function() {\n' + + ' widgetContext.dialogs.alert(`Device ` + deviceName + ` was successfully provisioned`, message).subscribe();\n' + + ' }, 100);\n' + + '}\n'; + const handleEmptyResultFunctionTemplate: TbFunction = '// Optional function body to handle empty result. \n' + '// Usually this happens when user cancels the action (for ex. by pressing phone back button). \n\n' + @@ -241,6 +250,8 @@ export const getDefaultProcessQrCodeFunction = () => processQrCodeFunction; export const getDefaultProcessLocationFunction = () => processLocationFunction; +export const getDefaultProvisioningSuccessFunction = () => provisioningSuccessFunction; + export const getDefaultGetLocationFunction = () => getLocationFunctionTemplate; export const getDefaultGetPhoneNumberFunction = () => getPhoneNumberFunctionTemplate; @@ -272,6 +283,9 @@ export const getDefaultHandleEmptyResultFunction = (type: WidgetMobileActionType case WidgetMobileActionType.takeScreenshot: message = 'Take screenshot action was cancelled!'; break; + case WidgetMobileActionType.provisioningDevice: + message = 'Provisioning device was not invoked!'; + break; } return handleEmptyResultFunctionTemplate.replace('--MESSAGE--', message); }; @@ -303,6 +317,9 @@ export const getDefaultHandleErrorFunction = (type: WidgetMobileActionType): TbF case WidgetMobileActionType.takeScreenshot: title = 'Failed to take screenshot'; break; + case WidgetMobileActionType.provisioningDevice: + title = 'Failed to make device provisioning'; + break; } return handleErrorFunctionTemplate.replace('--TITLE--', title); }; diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index eaf6b6105e..375646da55 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1292,6 +1292,26 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, ); } break; + case WidgetMobileActionType.provisioningDevice: + const deviceName = actionResult.device.name; + if (isNotEmptyTbFunction(mobileAction.handleProvisionSuccessFunction)) { + compileTbFunction(this.http, mobileAction.handleProvisionSuccessFunction, 'deviceName', '$event', 'widgetContext', 'entityId', + 'entityName', 'additionalParams', 'entityLabel').subscribe( + { + next: (compiled) => { + try { + compiled.execute(deviceName, $event, this.widgetContext, entityId, entityName, additionalParams, entityLabel); + } catch (e) { + console.error(e); + } + }, + error: (err) => { + console.error(err); + } + } + ); + } + break; case WidgetMobileActionType.scanQrCode: const code = actionResult.code; const format = actionResult.format; diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 5950dcf911..f92cffcf1c 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -47,6 +47,7 @@ import { WidgetConfigCallbacks } from '@home/components/widget/config/widget-con import { TbFunction } from '@shared/models/js-function.models'; import { FormProperty, jsonFormSchemaToFormProperties } from '@shared/models/dynamic-form.models'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { Device } from '@shared/models/device.models'; export enum widgetType { timeseries = 'timeseries', @@ -585,9 +586,26 @@ export enum WidgetMobileActionType { scanQrCode = 'scanQrCode', makePhoneCall = 'makePhoneCall', getLocation = 'getLocation', - takeScreenshot = 'takeScreenshot' + takeScreenshot = 'takeScreenshot', + provisioningDevice = 'provisioningDevice', } +export enum WidgetMobileProvisionType { + smartConfigEspTouch = 'SmartConfigEspTouch', + smartConfigEspTouchV2 = 'SmartConfigEspTouchV2', + wifi = 'wifi', + softAp = 'SoftAp', +} + +export const widgetMobileProvisionTypeTranslationMap = new Map( + [ + [ WidgetMobileProvisionType.smartConfigEspTouch, 'widget-action.mobile.provisioning-device.smart-config-esp-touch' ], + [ WidgetMobileProvisionType.smartConfigEspTouchV2, 'widget-action.mobile.provisioning-device.smart-config-esp-touch-v2' ], + [ WidgetMobileProvisionType.wifi, 'widget-action.mobile.provisioning-device.wifi' ], + [ WidgetMobileProvisionType.softAp, 'widget-action.mobile.provisioning-device.soft-ap' ] + ] +); + export const widgetActionTypes = Object.keys(WidgetActionType) as WidgetActionType[]; export const widgetActionTypeTranslationMap = new Map( @@ -612,7 +630,8 @@ export const widgetMobileActionTypeTranslationMap = new Map { result?: T; @@ -646,6 +670,10 @@ export interface WidgetMobileActionResult { hasError: boolean; } +export interface ProvisionSuccessDescriptor { + handleProvisionSuccessFunction: TbFunction; +} + export interface ProcessImageDescriptor { processImageFunction: TbFunction; } @@ -674,7 +702,8 @@ export type WidgetMobileActionDescriptors = ProcessImageDescriptor & LaunchMapDescriptor & ScanQrCodeDescriptor & MakePhoneCallDescriptor & - GetLocationDescriptor; + GetLocationDescriptor & + ProvisionSuccessDescriptor; export interface WidgetMobileActionDescriptor extends WidgetMobileActionDescriptors { type: WidgetMobileActionType; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index a584bb453b..27c85e7263 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -5593,6 +5593,16 @@ "URL": "URL", "url-required": "URL is required.", "mobile": { + "provisioning-device": { + "label": "Provisioning device", + "type": "Provisioning device type", + "select-type": "Select provisioning device type", + "type-required": "Provisioning device type is required", + "smart-config-esp-touch": "Smart Config ESP-Touch", + "smart-config-esp-touch-v2": "Smart Config ESP-Touch v2", + "wifi": "Wi-Fi Provisioning via Bluetooth Low Energy BLE/QR code", + "soft-ap": "SoftAP" + }, "action-type": "Mobile action type", "select-action-type": "Select mobile action type", "action-type-required": "Mobile action type is required", From d3c7c30d35c9f6a818cafd4d9b4c8fa7f30704b1 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Thu, 16 Jan 2025 16:39:21 +0200 Subject: [PATCH 007/116] added provsion type arg --- .../src/app/modules/home/components/widget/widget.component.ts | 3 +++ ui-ngx/src/app/shared/models/widget.models.ts | 1 + 2 files changed, 4 insertions(+) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index 375646da55..22821c3d88 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1205,6 +1205,9 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, case WidgetMobileActionType.takeScreenshot: argsObservable = of([]); break; + case WidgetMobileActionType.provisioningDevice: + argsObservable = of([mobileAction.provisionType]); + break; case WidgetMobileActionType.mapDirection: case WidgetMobileActionType.mapLocation: argsObservable = compileTbFunction(this.http, mobileAction.getLocationFunction, '$event', 'widgetContext', 'entityId', diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index f92cffcf1c..0a04ef06b9 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -672,6 +672,7 @@ export interface WidgetMobileActionResult { export interface ProvisionSuccessDescriptor { handleProvisionSuccessFunction: TbFunction; + provisionType: WidgetMobileProvisionType; } export interface ProcessImageDescriptor { From 54afdaa07a9593d975577ac5e386505f274918f2 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 6 Feb 2025 15:15:38 +0200 Subject: [PATCH 008/116] Do not copy latest to entity views when data was not saved on the main entity --- .../DefaultTelemetrySubscriptionService.java | 10 +++-- ...faultTelemetrySubscriptionServiceTest.java | 41 +++++++++++++++++++ .../server/common/data/EntityType.java | 12 ++++++ .../thingsboard/common/util/DonAsynchron.java | 6 +++ 4 files changed, 66 insertions(+), 3 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index cab2f18dc7..43e4b66c40 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -151,7 +151,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries())); } if (strategy.saveLatest()) { - copyLatestToEntityViews(tenantId, entityId, request.getEntries()); + addMainCallback(saveFuture, __ -> copyLatestToEntityViews(tenantId, entityId, request.getEntries())); } return saveFuture; } @@ -207,8 +207,8 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } private void copyLatestToEntityViews(TenantId tenantId, EntityId entityId, List ts) { - if (EntityType.DEVICE.equals(entityId.getEntityType()) || EntityType.ASSET.equals(entityId.getEntityType())) { - Futures.addCallback(this.tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), + if (entityId.getEntityType().isOneOf(EntityType.DEVICE, EntityType.ASSET)) { + Futures.addCallback(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), new FutureCallback<>() { @Override public void onSuccess(@Nullable List result) { @@ -312,6 +312,10 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer addMainCallback(saveFuture, result -> callback.onSuccess(null), callback::onFailure); } + private void addMainCallback(ListenableFuture saveFuture, Consumer onSuccess) { + DonAsynchron.withCallback(saveFuture, onSuccess, null, tsCallBackExecutor); + } + private void addMainCallback(ListenableFuture saveFuture, Consumer onSuccess, Consumer onFailure) { DonAsynchron.withCallback(saveFuture, onSuccess, onFailure, tsCallBackExecutor); } diff --git a/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java index 10fdd85504..4ded639c76 100644 --- a/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java @@ -71,6 +71,7 @@ import java.util.concurrent.ExecutorService; import java.util.stream.LongStream; import java.util.stream.Stream; +import static com.google.common.util.concurrent.Futures.immediateFailedFuture; import static com.google.common.util.concurrent.Futures.immediateFuture; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.BDDMockito.given; @@ -318,6 +319,46 @@ class DefaultTelemetrySubscriptionServiceTest { then(subscriptionManagerService).shouldHaveNoInteractions(); } + @Test + void shouldNotCopyLatestToEntityViewWhenTimeseriesSaveFailedOnMainEntity() { + // GIVEN + var entityView = new EntityView(new EntityViewId(UUID.randomUUID())); + entityView.setTenantId(tenantId); + entityView.setCustomerId(customerId); + entityView.setEntityId(entityId); + entityView.setKeys(new TelemetryEntityView(sampleTelemetry.stream().map(KvEntry::getKey).toList(), new AttributesEntityView())); + + // mock that there is one entity view + lenient().when(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId)).thenReturn(immediateFuture(List.of(entityView))); + // mock that save latest call for entity view is successful + lenient().when(tsService.saveLatest(tenantId, entityView.getId(), sampleTelemetry)).thenReturn(immediateFuture(listOfNNumbers(sampleTelemetry.size()))); + // mock TPI for entity view + lenient().when(partitionService.resolve(ServiceType.TB_CORE, tenantId, entityView.getId())).thenReturn(tpi); + + var request = TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .customerId(customerId) + .entityId(entityId) + .entries(sampleTelemetry) + .ttl(sampleTtl) + .strategy(new TimeseriesSaveRequest.Strategy(true, true, false)) + .callback(emptyCallback) + .build(); + + given(tsService.save(tenantId, entityId, sampleTelemetry, sampleTtl)).willReturn(immediateFailedFuture(new RuntimeException("failed to save latest on main entity"))); + + // WHEN + telemetryService.saveTimeseries(request); + + // THEN + // should save only time series for the main entity + then(tsService).should().save(tenantId, entityId, sampleTelemetry, sampleTtl); + then(tsService).shouldHaveNoMoreInteractions(); + + // should not send any WS updates + then(subscriptionManagerService).shouldHaveNoInteractions(); + } + @ParameterizedTest @MethodSource("booleanCombinations") void shouldCallCorrectApiBasedOnBooleanFlagsInTheSaveRequest(boolean saveTimeseries, boolean saveLatest, boolean sendWsUpdate) { diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 579fa863ba..84fc59022b 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -84,4 +84,16 @@ public enum EntityType { this.tableName = tableName; } + public boolean isOneOf(EntityType... types) { + if (types == null) { + return false; + } + for (EntityType type : types) { + if (this == type) { + return true; + } + } + return false; + } + } diff --git a/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java b/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java index f538d04f15..0e1193ef99 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java +++ b/common/util/src/main/java/org/thingsboard/common/util/DonAsynchron.java @@ -36,6 +36,9 @@ public class DonAsynchron { FutureCallback callback = new FutureCallback() { @Override public void onSuccess(T result) { + if (onSuccess == null) { + return; + } try { onSuccess.accept(result); } catch (Throwable th) { @@ -45,6 +48,9 @@ public class DonAsynchron { @Override public void onFailure(Throwable t) { + if (onFailure == null) { + return; + } onFailure.accept(t); } }; From b2b33199fea5fcf6940a2aca642931f332942376 Mon Sep 17 00:00:00 2001 From: Dmytro Skarzhynets Date: Thu, 6 Feb 2025 15:55:41 +0200 Subject: [PATCH 009/116] Corrections after code review --- .../DefaultTelemetrySubscriptionService.java | 96 +++++++++---------- ...faultTelemetrySubscriptionServiceTest.java | 2 +- 2 files changed, 48 insertions(+), 50 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java index 43e4b66c40..5b5054ae38 100644 --- a/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java +++ b/application/src/main/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionService.java @@ -150,7 +150,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer if (strategy.sendWsUpdate()) { addWsCallback(saveFuture, success -> onTimeSeriesUpdate(tenantId, entityId, request.getEntries())); } - if (strategy.saveLatest()) { + if (strategy.saveLatest() && entityId.getEntityType().isOneOf(EntityType.DEVICE, EntityType.ASSET)) { addMainCallback(saveFuture, __ -> copyLatestToEntityViews(tenantId, entityId, request.getEntries())); } return saveFuture; @@ -207,58 +207,56 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } private void copyLatestToEntityViews(TenantId tenantId, EntityId entityId, List ts) { - if (entityId.getEntityType().isOneOf(EntityType.DEVICE, EntityType.ASSET)) { - Futures.addCallback(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), - new FutureCallback<>() { - @Override - public void onSuccess(@Nullable List result) { - if (result != null && !result.isEmpty()) { - Map> tsMap = new HashMap<>(); - for (TsKvEntry entry : ts) { - tsMap.computeIfAbsent(entry.getKey(), s -> new ArrayList<>()).add(entry); - } - for (EntityView entityView : result) { - List keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ? - entityView.getKeys().getTimeseries() : new ArrayList<>(tsMap.keySet()); - List entityViewLatest = new ArrayList<>(); - long startTs = entityView.getStartTimeMs(); - long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs(); - for (String key : keys) { - List entries = tsMap.get(key); - if (entries != null) { - Optional tsKvEntry = entries.stream() - .filter(entry -> entry.getTs() > startTs && entry.getTs() <= endTs) - .max(Comparator.comparingLong(TsKvEntry::getTs)); - tsKvEntry.ifPresent(entityViewLatest::add); - } - } - if (!entityViewLatest.isEmpty()) { - saveTimeseries(TimeseriesSaveRequest.builder() - .tenantId(tenantId) - .entityId(entityView.getId()) - .entries(entityViewLatest) - .strategy(TimeseriesSaveRequest.Strategy.LATEST_AND_WS) - .callback(new FutureCallback<>() { - @Override - public void onSuccess(@Nullable Void tmp) {} - - @Override - public void onFailure(Throwable t) { - log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), entityViewLatest, t); - } - }) - .build()); + Futures.addCallback(tbEntityViewService.findEntityViewsByTenantIdAndEntityIdAsync(tenantId, entityId), + new FutureCallback<>() { + @Override + public void onSuccess(@Nullable List result) { + if (result != null && !result.isEmpty()) { + Map> tsMap = new HashMap<>(); + for (TsKvEntry entry : ts) { + tsMap.computeIfAbsent(entry.getKey(), s -> new ArrayList<>()).add(entry); + } + for (EntityView entityView : result) { + List keys = entityView.getKeys() != null && entityView.getKeys().getTimeseries() != null ? + entityView.getKeys().getTimeseries() : new ArrayList<>(tsMap.keySet()); + List entityViewLatest = new ArrayList<>(); + long startTs = entityView.getStartTimeMs(); + long endTs = entityView.getEndTimeMs() == 0 ? Long.MAX_VALUE : entityView.getEndTimeMs(); + for (String key : keys) { + List entries = tsMap.get(key); + if (entries != null) { + Optional tsKvEntry = entries.stream() + .filter(entry -> entry.getTs() > startTs && entry.getTs() <= endTs) + .max(Comparator.comparingLong(TsKvEntry::getTs)); + tsKvEntry.ifPresent(entityViewLatest::add); } } + if (!entityViewLatest.isEmpty()) { + saveTimeseries(TimeseriesSaveRequest.builder() + .tenantId(tenantId) + .entityId(entityView.getId()) + .entries(entityViewLatest) + .strategy(TimeseriesSaveRequest.Strategy.LATEST_AND_WS) + .callback(new FutureCallback<>() { + @Override + public void onSuccess(@Nullable Void tmp) {} + + @Override + public void onFailure(Throwable t) { + log.error("[{}][{}] Failed to save entity view latest timeseries: {}", tenantId, entityView.getId(), entityViewLatest, t); + } + }) + .build()); + } } } + } - @Override - public void onFailure(Throwable t) { - log.error("Error while finding entity views by tenantId and entityId", t); - } - }, MoreExecutors.directExecutor()); - } + @Override + public void onFailure(Throwable t) { + log.error("Error while finding entity views by tenantId and entityId", t); + } + }, MoreExecutors.directExecutor()); } private void onAttributesUpdate(TenantId tenantId, EntityId entityId, String scope, List attributes, boolean notifyDevice) { @@ -313,7 +311,7 @@ public class DefaultTelemetrySubscriptionService extends AbstractSubscriptionSer } private void addMainCallback(ListenableFuture saveFuture, Consumer onSuccess) { - DonAsynchron.withCallback(saveFuture, onSuccess, null, tsCallBackExecutor); + addMainCallback(saveFuture, onSuccess, null); } private void addMainCallback(ListenableFuture saveFuture, Consumer onSuccess, Consumer onFailure) { diff --git a/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java b/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java index 4ded639c76..60a16c16a4 100644 --- a/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/telemetry/DefaultTelemetrySubscriptionServiceTest.java @@ -345,7 +345,7 @@ class DefaultTelemetrySubscriptionServiceTest { .callback(emptyCallback) .build(); - given(tsService.save(tenantId, entityId, sampleTelemetry, sampleTtl)).willReturn(immediateFailedFuture(new RuntimeException("failed to save latest on main entity"))); + given(tsService.save(tenantId, entityId, sampleTelemetry, sampleTtl)).willReturn(immediateFailedFuture(new RuntimeException("failed to save data on main entity"))); // WHEN telemetryService.saveTimeseries(request); From bf6301a1de1ba17233fc65715f7e01cbcf8ee59e Mon Sep 17 00:00:00 2001 From: Sergey Matvienko Date: Mon, 24 Feb 2025 11:58:21 +0100 Subject: [PATCH 010/116] StatsPersistTick scheduled future cancel on actor destroy --- .../org/thingsboard/server/actors/ActorSystemContext.java | 5 +++-- .../thingsboard/server/actors/service/ComponentActor.java | 8 +++++++- .../actors/shared/AbstractContextAwareMsgProcessor.java | 5 +++-- .../server/actors/shared/ComponentMsgProcessor.java | 6 ++++-- 4 files changed, 17 insertions(+), 7 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 1c18a31f68..c15c87be1c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -127,6 +127,7 @@ import java.io.StringWriter; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @Slf4j @@ -763,9 +764,9 @@ public class ActorSystemContext { appActor.tellWithHighPriority(tbActorMsg); } - public void schedulePeriodicMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs, long periodInMs) { + public ScheduledFuture schedulePeriodicMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs, long periodInMs) { log.debug("Scheduling periodic msg {} every {} ms with delay {} ms", msg, periodInMs, delayInMs); - getScheduler().scheduleWithFixedDelay(() -> ctx.tell(msg), delayInMs, periodInMs, TimeUnit.MILLISECONDS); + return getScheduler().scheduleWithFixedDelay(() -> ctx.tell(msg), delayInMs, periodInMs, TimeUnit.MILLISECONDS); } public void scheduleMsgWithDelay(TbActorRef ctx, TbActorMsg msg, long delayInMs) { diff --git a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java index 5aea88d622..bf50273814 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java @@ -29,6 +29,9 @@ import org.thingsboard.server.common.msg.TbActorStopReason; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; +import java.util.Optional; +import java.util.concurrent.ScheduledFuture; + /** * @author Andrew Shvayka */ @@ -41,6 +44,7 @@ public abstract class ComponentActor statsScheduledFuture = null; public ComponentActor(ActorSystemContext systemContext, TenantId tenantId, T id) { super(systemContext); @@ -75,7 +79,7 @@ public abstract class ComponentActor x.cancel(false)); + statsScheduledFuture = null; } catch (Exception e) { log.warn("[{}][{}] Failed to stop {} processor: {}", tenantId, id, id.getEntityType(), e.getMessage()); logAndPersist("OnStop", e, true); diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java index 571d79d18c..a34a8ca537 100644 --- a/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/shared/AbstractContextAwareMsgProcessor.java @@ -21,6 +21,7 @@ import org.thingsboard.server.actors.TbActorCtx; import org.thingsboard.server.common.msg.TbActorMsg; import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.ScheduledFuture; @Slf4j public abstract class AbstractContextAwareMsgProcessor { @@ -36,8 +37,8 @@ public abstract class AbstractContextAwareMsgProcessor { return systemContext.getScheduler(); } - protected void schedulePeriodicMsgWithDelay(TbActorCtx ctx, TbActorMsg msg, long delayInMs, long periodInMs) { - systemContext.schedulePeriodicMsgWithDelay(ctx, msg, delayInMs, periodInMs); + protected ScheduledFuture schedulePeriodicMsgWithDelay(TbActorCtx ctx, TbActorMsg msg, long delayInMs, long periodInMs) { + return systemContext.schedulePeriodicMsgWithDelay(ctx, msg, delayInMs, periodInMs); } protected void scheduleMsgWithDelay(TbActorCtx ctx, TbActorMsg msg, long delayInMs) { diff --git a/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java b/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java index 298874cc51..c37b35400c 100644 --- a/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/shared/ComponentMsgProcessor.java @@ -27,6 +27,8 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; import org.thingsboard.server.common.msg.queue.RuleNodeException; +import java.util.concurrent.ScheduledFuture; + @Slf4j public abstract class ComponentMsgProcessor extends AbstractContextAwareMsgProcessor { @@ -77,8 +79,8 @@ public abstract class ComponentMsgProcessor extends Abstract start(context); } - public void scheduleStatsPersistTick(TbActorCtx context, long statsPersistFrequency) { - schedulePeriodicMsgWithDelay(context, StatsPersistTick.INSTANCE, statsPersistFrequency, statsPersistFrequency); + public ScheduledFuture scheduleStatsPersistTick(TbActorCtx context, long statsPersistFrequency) { + return schedulePeriodicMsgWithDelay(context, StatsPersistTick.INSTANCE, statsPersistFrequency, statsPersistFrequency); } protected boolean checkMsgValid(TbMsg tbMsg) { From 1b0b10a15aa15fa0204f26fc4d10f1138b91ac47 Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Wed, 5 Feb 2025 14:45:00 +0100 Subject: [PATCH 011/116] Usage of long refactored to int in LinkedHashMapRemoveEldest class Signed-off-by: Oleksandra Matviienko --- .../server/actors/ActorSystemContext.java | 2 +- .../common/util/LinkedHashMapRemoveEldest.java | 4 ++-- .../common/util/LinkedHashMapRemoveEldestTest.java | 14 +++++++------- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java index 1c18a31f68..b13cf8e490 100644 --- a/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java +++ b/application/src/main/java/org/thingsboard/server/actors/ActorSystemContext.java @@ -489,7 +489,7 @@ public class ActorSystemContext { @Value("${actors.session.max_concurrent_sessions_per_device:1}") @Getter - private long maxConcurrentSessionsPerDevice; + private int maxConcurrentSessionsPerDevice; @Value("${actors.session.sync.timeout:10000}") @Getter diff --git a/common/util/src/main/java/org/thingsboard/common/util/LinkedHashMapRemoveEldest.java b/common/util/src/main/java/org/thingsboard/common/util/LinkedHashMapRemoveEldest.java index 99f766d4f6..9798706d32 100644 --- a/common/util/src/main/java/org/thingsboard/common/util/LinkedHashMapRemoveEldest.java +++ b/common/util/src/main/java/org/thingsboard/common/util/LinkedHashMapRemoveEldest.java @@ -34,10 +34,10 @@ import java.util.function.BiConsumer; @ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class LinkedHashMapRemoveEldest extends LinkedHashMap { - final long maxEntries; + final int maxEntries; final BiConsumer removalConsumer; - public LinkedHashMapRemoveEldest(long maxEntries, BiConsumer removalConsumer) { + public LinkedHashMapRemoveEldest(int maxEntries, BiConsumer removalConsumer) { this.maxEntries = maxEntries; this.removalConsumer = removalConsumer; } diff --git a/common/util/src/test/java/org/thingsboard/common/util/LinkedHashMapRemoveEldestTest.java b/common/util/src/test/java/org/thingsboard/common/util/LinkedHashMapRemoveEldestTest.java index e52dd895a0..277c9a95c9 100644 --- a/common/util/src/test/java/org/thingsboard/common/util/LinkedHashMapRemoveEldestTest.java +++ b/common/util/src/test/java/org/thingsboard/common/util/LinkedHashMapRemoveEldestTest.java @@ -27,10 +27,10 @@ import static org.hamcrest.MatcherAssert.assertThat; public class LinkedHashMapRemoveEldestTest { - public static final long MAX_ENTRIES = 10L; - long removeCount = 0; + public static final int MAX_ENTRIES = 10; + int removeCount = 0; - void removalConsumer(Long id, String name) { + void removalConsumer(Integer id, String name) { removeCount++; assertThat(id, is(Matchers.lessThan(MAX_ENTRIES))); assertThat(name, is(id.toString())); @@ -39,7 +39,7 @@ public class LinkedHashMapRemoveEldestTest { @Test public void givenMap_whenOverSized_thenVerifyRemovedEldest() { //given - LinkedHashMapRemoveEldest map = + LinkedHashMapRemoveEldest map = new LinkedHashMapRemoveEldest<>(MAX_ENTRIES, this::removalConsumer); assertThat(map.getMaxEntries(), is(MAX_ENTRIES)); @@ -49,14 +49,14 @@ public class LinkedHashMapRemoveEldestTest { assertThat(map.size(), is(0)); //when - for (long i = 0; i < MAX_ENTRIES * 2; i++) { + for (int i = 0; i < MAX_ENTRIES * 2; i++) { map.put(i, String.valueOf(i)); } //then - assertThat((long) map.size(), is(MAX_ENTRIES)); + assertThat( map.size(), is(MAX_ENTRIES)); assertThat(removeCount, is(MAX_ENTRIES)); - for (long i = MAX_ENTRIES; i < MAX_ENTRIES * 2; i++) { + for (int i = MAX_ENTRIES; i < MAX_ENTRIES * 2; i++) { assertThat(map.get(i), is(String.valueOf(i))); } } From 605fa385c993551f2049a5dd1899e8e3d7059718 Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Wed, 26 Feb 2025 12:11:12 +0100 Subject: [PATCH 012/116] Tests are fixed Signed-off-by: Oleksandra Matviienko --- .../server/actors/device/DeviceActorMessageProcessorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/test/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessorTest.java b/application/src/test/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessorTest.java index 4f571d4fe6..8408f9868f 100644 --- a/application/src/test/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessorTest.java +++ b/application/src/test/java/org/thingsboard/server/actors/device/DeviceActorMessageProcessorTest.java @@ -49,7 +49,7 @@ public class DeviceActorMessageProcessorTest { public void setUp() { systemContext = mock(ActorSystemContext.class); deviceService = mock(DeviceService.class); - willReturn((long)MAX_CONCURRENT_SESSIONS_PER_DEVICE).given(systemContext).getMaxConcurrentSessionsPerDevice(); + willReturn(MAX_CONCURRENT_SESSIONS_PER_DEVICE).given(systemContext).getMaxConcurrentSessionsPerDevice(); willReturn(deviceService).given(systemContext).getDeviceService(); processor = new DeviceActorMessageProcessor(systemContext, tenantId, deviceId); willReturn(mock(TbCoreToTransportService.class)).given(systemContext).getTbCoreToTransportService(); @@ -58,7 +58,7 @@ public class DeviceActorMessageProcessorTest { @Test public void givenSystemContext_whenNewInstance_thenVerifySessionMapMaxSize() { assertThat(processor.sessions, instanceOf(LinkedHashMapRemoveEldest.class)); - assertThat(processor.sessions.getMaxEntries(), is((long)MAX_CONCURRENT_SESSIONS_PER_DEVICE)); + assertThat(processor.sessions.getMaxEntries(), is(MAX_CONCURRENT_SESSIONS_PER_DEVICE)); assertThat(processor.sessions.getRemovalConsumer(), notNullValue()); } From acc5764565241b28e81d51a42760136804f732e9 Mon Sep 17 00:00:00 2001 From: trikimiki <41070061+trikimiki@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:31:18 +0200 Subject: [PATCH 013/116] rewrite volume check/create scripts add option to skip ownership change (fix for Docker Desktop "Synchronized file shares " feature) --- docker/compose-utils.sh | 72 ++++++++++++++++++++++++----- docker/docker-check-log-folders.sh | 9 +++- docker/docker-create-log-folders.sh | 2 +- 3 files changed, 68 insertions(+), 15 deletions(-) diff --git a/docker/compose-utils.sh b/docker/compose-utils.sh index d5e60bee7f..dd2d2890fc 100755 --- a/docker/compose-utils.sh +++ b/docker/compose-utils.sh @@ -182,29 +182,77 @@ function permissionList() { } function checkFolders() { + CREATE=false + SKIP_CHOWN=false + for i in "$@" + do + case $i in + --create) + CREATE=true + shift + ;; + --skipChown) + SKIP_CHOWN=true + shift + ;; + *) + # unknown option + ;; + esac + done EXIT_CODE=0 PERMISSION_LIST=$(permissionList) || exit $? set -e while read -r USR GRP DIR do - if [ -z "$DIR" ]; then # skip empty lines + IS_EXIST_CHECK_PASSED=false + IS_OWNER_CHECK_PASSED=false + + # skip empty lines + if [ -z "$DIR" ]; then continue fi - MESSAGE="Checking user ${USR} group ${GRP} dir ${DIR}" - if [[ -d "$DIR" ]] && - [[ $(ls -ldn "$DIR" | awk '{print $3}') -eq "$USR" ]] && - [[ $(ls -ldn "$DIR" | awk '{print $4}') -eq "$GRP" ]] - then - MESSAGE="$MESSAGE OK" + + # checks section + echo "Checking if dir ${DIR} exists..." + if [[ -d "$DIR" ]]; then + echo "> OK" + IS_EXIST_CHECK_PASSED=true + if [ "$SKIP_CHOWN" = false ]; then + echo "Checking user ${USR} group ${GRP} ownership for dir ${DIR}..." + if [[ $(ls -ldn "$DIR" | awk '{print $3}') -eq "$USR" ]] && [[ $(ls -ldn "$DIR" | awk '{print $4}') -eq "$GRP" ]]; then + echo "> OK" + IS_OWNER_CHECK_PASSED=true + else + echo "...ownership check failed" + if [ "$CREATE" = false ]; then + EXIT_CODE=1 + fi + fi + fi else - if [ "$1" = "--create" ]; then - echo "Create and chown: user ${USR} group ${GRP} dir ${DIR}" - mkdir -p "$DIR" && sudo chown -R "$USR":"$GRP" "$DIR" - else - echo "$MESSAGE FAILED" + echo "...does not exist" + if [ "$CREATE" = false ]; then EXIT_CODE=1 fi fi + + # create/chown section + if [ "$CREATE" = true ]; then + if [ "$IS_EXIST_CHECK_PASSED" = false ]; then + echo "...will create dir ${DIR}" + if [ "$SKIP_CHOWN" = false ]; then + echo "...will change ownership to user ${USR} group ${GRP} for dir ${DIR}" + mkdir -p "$DIR" && sudo chown -R "$USR":"$GRP" "$DIR" && echo "> OK" + else + mkdir -p "$DIR" && echo "> OK" + fi + elif [ "$IS_OWNER_CHECK_PASSED" = false ] && [ "$SKIP_CHOWN" = false ]; then + echo "...will change ownership to user ${USR} group ${GRP} for dir ${DIR}" + sudo chown -R "$USR":"$GRP" "$DIR" && echo "> OK" + fi + fi + done < <(echo "$PERMISSION_LIST") return $EXIT_CODE } diff --git a/docker/docker-check-log-folders.sh b/docker/docker-check-log-folders.sh index e293968a69..22e91ea3f3 100755 --- a/docker/docker-check-log-folders.sh +++ b/docker/docker-check-log-folders.sh @@ -17,5 +17,10 @@ set -e source compose-utils.sh -checkFolders || exit $? -echo "OK" +if checkFolders "$@" ; then + echo "------" + echo "All checks have passed" +else + echo "------" + echo "Some checks did not pass - check the output" +fi \ No newline at end of file diff --git a/docker/docker-create-log-folders.sh b/docker/docker-create-log-folders.sh index 098ffabb31..ed66d4e156 100755 --- a/docker/docker-create-log-folders.sh +++ b/docker/docker-create-log-folders.sh @@ -17,4 +17,4 @@ set -e source compose-utils.sh -checkFolders --create +checkFolders --create "$@" From 801a1baab488b9d47352499e856da1d9506a5eda Mon Sep 17 00:00:00 2001 From: trikimiki <41070061+trikimiki@users.noreply.github.com> Date: Wed, 26 Feb 2025 18:37:43 +0200 Subject: [PATCH 014/116] remove duplicate from volume checklist --- docker/compose-utils.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/docker/compose-utils.sh b/docker/compose-utils.sh index dd2d2890fc..55615800b4 100755 --- a/docker/compose-utils.sh +++ b/docker/compose-utils.sh @@ -131,7 +131,6 @@ function additionalStartupServices() { function permissionList() { PERMISSION_LIST=" 799 799 tb-node/log - 799 799 tb-transports/coap/log 799 799 tb-transports/lwm2m/log 799 799 tb-transports/http/log 799 799 tb-transports/mqtt/log From 07256796897cbeef008c4b2b258c78d8fee8f633 Mon Sep 17 00:00:00 2001 From: trikimiki <41070061+trikimiki@users.noreply.github.com> Date: Thu, 27 Feb 2025 14:59:40 +0200 Subject: [PATCH 015/116] remove checkFolders from other scripts reason - it breaks running TB for MacOS users; will update site documentation accordingly --- docker/docker-install-tb.sh | 2 -- docker/docker-start-services.sh | 2 -- docker/docker-upgrade-tb.sh | 2 -- 3 files changed, 6 deletions(-) diff --git a/docker/docker-install-tb.sh b/docker/docker-install-tb.sh index 1956e50eac..25f089afb4 100755 --- a/docker/docker-install-tb.sh +++ b/docker/docker-install-tb.sh @@ -51,8 +51,6 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $? ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? -checkFolders --create || exit $? - if [ ! -z "${ADDITIONAL_STARTUP_SERVICES// }" ]; then COMPOSE_ARGS="\ diff --git a/docker/docker-start-services.sh b/docker/docker-start-services.sh index 3cdf10d00f..39dc57c1de 100755 --- a/docker/docker-start-services.sh +++ b/docker/docker-start-services.sh @@ -29,8 +29,6 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $? ADDITIONAL_COMPOSE_MONITORING_ARGS=$(additionalComposeMonitoringArgs) || exit $? -checkFolders --create || exit $? - COMPOSE_ARGS="\ -f docker-compose.yml ${ADDITIONAL_CACHE_ARGS} ${ADDITIONAL_COMPOSE_ARGS} ${ADDITIONAL_COMPOSE_QUEUE_ARGS} ${ADDITIONAL_COMPOSE_MONITORING_ARGS} \ up -d" diff --git a/docker/docker-upgrade-tb.sh b/docker/docker-upgrade-tb.sh index 3be5fbc14b..5a34e29aa9 100755 --- a/docker/docker-upgrade-tb.sh +++ b/docker/docker-upgrade-tb.sh @@ -44,8 +44,6 @@ ADDITIONAL_CACHE_ARGS=$(additionalComposeCacheArgs) || exit $? ADDITIONAL_STARTUP_SERVICES=$(additionalStartupServices) || exit $? -checkFolders --create || exit $? - COMPOSE_ARGS_PULL="\ -f docker-compose.yml ${ADDITIONAL_CACHE_ARGS} ${ADDITIONAL_COMPOSE_ARGS} ${ADDITIONAL_COMPOSE_QUEUE_ARGS} \ pull \ From f772bab21843b6935ff44ac99e7d96a74760d4c1 Mon Sep 17 00:00:00 2001 From: trikimiki <41070061+trikimiki@users.noreply.github.com> Date: Thu, 27 Feb 2025 16:16:05 +0200 Subject: [PATCH 016/116] bump zookeeper version --- docker/docker-compose.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index 69b7722459..1cee5ad5ad 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -20,7 +20,7 @@ version: '3.0' services: zookeeper: restart: always - image: "zookeeper:3.8.0" + image: "zookeeper:3.8.1" ports: - "2181" environment: From dcc88a619e5837964f46d98d6bc67a82f075e9bd Mon Sep 17 00:00:00 2001 From: Oleksandra Matviienko Date: Sun, 2 Mar 2025 19:24:14 +0100 Subject: [PATCH 017/116] Tests for scheduleStatsPersistTick and destroy methods in ComponentActor were written. Signed-off-by: Oleksandra Matviienko --- .../server/actors/service/ComponentActor.java | 2 +- .../actors/service/ComponentActorTest.java | 74 +++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) create mode 100644 application/src/test/java/org/thingsboard/server/actors/service/ComponentActorTest.java diff --git a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java index bf50273814..8203528e41 100644 --- a/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/service/ComponentActor.java @@ -77,7 +77,7 @@ public abstract class ComponentActor statsScheduledFuture = Mockito.mock(ScheduledFuture.class); + ActorSystemContext systemContext = Mockito.mock(ActorSystemContext.class); + ReflectionTestUtils.setField(componentActor, "systemContext", systemContext); + ComponentMsgProcessor processor = Mockito.mock(ComponentMsgProcessor.class); + componentActor.processor = processor; + BDDMockito.willReturn(statsScheduledFuture).given(processor).scheduleStatsPersistTick(any(), anyLong()); + BDDMockito.willCallRealMethod().given(componentActor).scheduleStatsPersistTick(); + + componentActor.scheduleStatsPersistTick(); + + Assertions.assertNotNull(componentActor.statsScheduledFuture); + } + + @Test + void destroyTest() { + ScheduledFuture statsScheduledFuture = Mockito.mock(ScheduledFuture.class); + componentActor.statsScheduledFuture = statsScheduledFuture; + Assertions.assertNotNull(componentActor.statsScheduledFuture); + Throwable cause = new Throwable(); + EntityId id = Mockito.mock(EntityId.class); + ReflectionTestUtils.setField(componentActor, "id", id); + BDDMockito.willCallRealMethod().given(componentActor).destroy(any(), any()); + + componentActor.destroy(TbActorStopReason.STOPPED, cause); + + Mockito.verify(statsScheduledFuture).cancel(false); + Assertions.assertNull(componentActor.statsScheduledFuture); + } + +} From 3d3a8ffc057d98820f0b612265fb8ca5223bed13 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 15:55:39 +0200 Subject: [PATCH 018/116] Added debug settings service --- .../calculated-fields-table-config.ts | 61 ++++++----------- .../calculated-fields-table.component.ts | 11 ++- ...ntity-debug-settings-button.component.html | 2 +- .../entity-debug-settings-button.component.ts | 46 +++++-------- .../debug/entity-debug-settings.service.ts | 68 +++++++++++++++++++ .../home/components/home-components.module.ts | 4 +- ui-ngx/src/app/shared/models/entity.models.ts | 11 +++ ui-ngx/src/app/shared/shared.module.ts | 2 + 8 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 6932860be4..9cb04ee04a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -29,10 +29,7 @@ import { AppState } from '@core/core.state'; import { getCurrentAuthState, getCurrentAuthUser } from '@core/auth/auth.selectors'; import { DestroyRef, Renderer2 } from '@angular/core'; import { EntityDebugSettings } from '@shared/models/entity.models'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { TbPopoverService } from '@shared/components/popover.service'; -import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { @@ -53,6 +50,7 @@ import { } from './components/public-api'; import { ImportExportService } from '@shared/import-export/import-export.service'; import { isObject } from '@core/utils'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; export class CalculatedFieldsTableConfig extends EntityTableConfig { @@ -71,12 +69,11 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private destroyRef: DestroyRef, private renderer: Renderer2, public entityName: string, - private importExportService: ImportExportService + private importExportService: ImportExportService, + private entityDebugSettingsService: EntityDebugSettingsService, ) { super(); this.tableTitle = this.translate.instant('entity.type-calculated-fields'); @@ -131,10 +128,10 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.getDebugConfigLabel(entity?.debugSettings), + nameFunction: entity => this.entityDebugSettingsService.getDebugConfigLabel(entity?.debugSettings), icon: 'mdi:bug', isEnabled: () => true, - iconFunction: ({ debugSettings }) => this.isDebugActive(debugSettings?.allEnabledUntil) || debugSettings?.failuresEnabled ? 'mdi:bug' : 'mdi:bug-outline', + iconFunction: ({ debugSettings }) => this.entityDebugSettingsService.isDebugActive(debugSettings?.allEnabledUntil) || debugSettings?.failuresEnabled ? 'mdi:bug' : 'mdi:bug-outline', onAction: ($event, entity) => this.onOpenDebugConfig($event, entity), }, { @@ -160,26 +157,20 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig { - this.onDebugConfigChanged(id.id, settings); - debugStrategyPopover.hide(); - }); - } + + this.entityDebugSettingsService.viewContainerRef = viewContainerRef; + this.entityDebugSettingsService.renderer = this.renderer; + + this.entityDebugSettingsService.openDebugStrategyPanel({ + debugSettings, + debugConfig: { + debugLimitsConfiguration: this.calculatedFieldsDebugPerTenantLimitsConfiguration, + maxDebugModeDuration: this.maxDebugModeDuration, + entityLabel: this.translate.instant('debug-settings.calculated-field'), + additionalActionConfig, + }, + onSettingsAppliedFn: settings => this.onDebugConfigChanged(id.id, settings) + }, $event.target as Element); } private editCalculatedField(calculatedField: CalculatedField, isDirty = false): void { @@ -239,20 +230,6 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.updateData()); } - private getDebugConfigLabel(debugSettings: EntityDebugSettings): string { - const isDebugActive = this.isDebugActive(debugSettings?.allEnabledUntil); - - if (!isDebugActive) { - return debugSettings?.failuresEnabled ? this.translate.instant('debug-settings.failures') : this.translate.instant('common.disabled'); - } else { - return this.durationLeft.transform(debugSettings?.allEnabledUntil); - } - } - - private isDebugActive(allEnabledUntil: number): boolean { - return allEnabledUntil > new Date().getTime(); - } - private onDebugConfigChanged(id: string, debugSettings: EntityDebugSettings): void { this.calculatedFieldsService.getCalculatedFieldById(id).pipe( switchMap(field => this.calculatedFieldsService.saveCalculatedField({ ...field, debugSettings })), diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index be6fb11480..82d96b9557 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -31,10 +31,9 @@ import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { CalculatedFieldsTableConfig } from '@home/components/calculated-fields/calculated-fields-table-config'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; -import { TbPopoverService } from '@shared/components/popover.service'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { ImportExportService } from '@shared/import-export/import-export.service'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @Component({ selector: 'tb-calculated-fields-table', @@ -56,11 +55,10 @@ export class CalculatedFieldsTableComponent { private translate: TranslateService, private dialog: MatDialog, private store: Store, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private cd: ChangeDetectorRef, private renderer: Renderer2, private importExportService: ImportExportService, + private entityDebugSettingsService: EntityDebugSettingsService, private destroyRef: DestroyRef) { effect(() => { @@ -71,12 +69,11 @@ export class CalculatedFieldsTableComponent { this.dialog, this.entityId(), this.store, - this.durationLeft, - this.popoverService, this.destroyRef, this.renderer, this.entityName(), - this.importExportService + this.importExportService, + this.entityDebugSettingsService, ); this.cd.markForCheck(); } diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html index a6033df8cb..4243044fc8 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.html @@ -21,7 +21,7 @@ #matButton [class.active]="((isDebugAllActive$ | async) || failuresEnabled) && !disabled" [disabled]="disabled" - (click)="openDebugStrategyPanel($event, matButton)"> + (click)="onOpenDebugStrategyPanel($event, matButton)"> bug_report @if (isDebugAllActive$ | async) { {{ (allEnabled$ | async) === false ? (allEnabledUntil | durationLeft) : (maxDebugModeDuration | milliSecondsToTimeString: true : true) }} diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts index 852da5f7bf..99a08494fc 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts @@ -20,15 +20,11 @@ import { Component, forwardRef, Input, - Renderer2, - ViewContainerRef } from '@angular/core'; import { CommonModule } from '@angular/common'; import { SharedModule } from '@shared/shared.module'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; -import { TbPopoverService } from '@shared/components/popover.service'; import { MatButton } from '@angular/material/button'; -import { EntityDebugSettingsPanelComponent } from './entity-debug-settings-panel.component'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { BehaviorSubject, of, shareReplay, timer } from 'rxjs'; import { SECOND, MINUTE } from '@shared/models/time/time.models'; @@ -38,6 +34,7 @@ import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @Component({ selector: 'tb-entity-debug-settings-button', @@ -54,6 +51,7 @@ import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/f useExisting: forwardRef(() => EntityDebugSettingsButtonComponent), multi: true }, + EntityDebugSettingsService ], changeDetection: ChangeDetectionStrategy.OnPush }) @@ -92,11 +90,9 @@ export class EntityDebugSettingsButtonComponent implements ControlValueAccessor private propagateChange: (settings: EntityDebugSettings) => void = () => {}; - constructor(private popoverService: TbPopoverService, - private renderer: Renderer2, - private store: Store, - private viewContainerRef: ViewContainerRef, + constructor(private store: Store, private fb: FormBuilder, + private entityDebugSettingsService: EntityDebugSettingsService, private cd : ChangeDetectorRef, ) { this.debugSettingsFormGroup.valueChanges.pipe( @@ -118,33 +114,23 @@ export class EntityDebugSettingsButtonComponent implements ControlValueAccessor return this.debugSettingsFormGroup.get('allEnabledUntil').value; } - openDebugStrategyPanel($event: Event, matButton: MatButton): void { + onOpenDebugStrategyPanel($event: Event, matButton: MatButton): void { if ($event) { $event.stopPropagation(); } - const trigger = matButton._elementRef.nativeElement; - const debugSettings = this.debugSettingsFormGroup.value; - - if (this.popoverService.hasPopover(trigger)) { - this.popoverService.hidePopover(trigger); - } else { - const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, - this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, - { - ...debugSettings, - maxDebugModeDuration: this.maxDebugModeDuration, - debugLimitsConfiguration: this.debugLimitsConfiguration, - entityLabel: this.entityLabel, - additionalActionConfig: this.additionalActionConfig, - }, - {}, - {}, {}, true); - debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe((settings: EntityDebugSettings) => { + this.entityDebugSettingsService.openDebugStrategyPanel({ + debugSettings: this.debugSettingsFormGroup.value, + debugConfig: { + maxDebugModeDuration: this.maxDebugModeDuration, + debugLimitsConfiguration: this.debugLimitsConfiguration, + entityLabel: this.entityLabel, + additionalActionConfig: this.additionalActionConfig, + }, + onSettingsAppliedFn: settings => { this.debugSettingsFormGroup.patchValue(settings); this.cd.markForCheck(); - debugStrategyPopover.hide(); - }); - } + } + }, matButton._elementRef.nativeElement); } registerOnChange(fn: (settings: EntityDebugSettings) => void): void { diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts new file mode 100644 index 0000000000..c53bc5b777 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts @@ -0,0 +1,68 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { Injectable, Optional, Renderer2, ViewContainerRef } from '@angular/core'; +import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; +import { EntityDebugSettingPanelConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { TbPopoverService } from '@shared/components/popover.service'; +import { TranslateService } from '@ngx-translate/core'; +import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; + +@Injectable() +export class EntityDebugSettingsService { + + constructor( + private popoverService: TbPopoverService, + @Optional() public renderer: Renderer2, + @Optional() public viewContainerRef: ViewContainerRef, + private translate: TranslateService, + private durationLeft: DurationLeftPipe, + ) {} + + openDebugStrategyPanel(panelConfig: EntityDebugSettingPanelConfig, trigger: Element): void { + if (this.popoverService.hasPopover(trigger)) { + this.popoverService.hidePopover(trigger); + } else { + const debugStrategyPopover = this.popoverService.displayPopover(trigger, this.renderer, + this.viewContainerRef, EntityDebugSettingsPanelComponent, 'bottom', true, null, + { + ...panelConfig.debugSettings, + ...panelConfig.debugConfig, + }, + {}, + {}, {}, true); + debugStrategyPopover.tbComponentRef.instance.onSettingsApplied.subscribe(settings => { + panelConfig.onSettingsAppliedFn(settings); + debugStrategyPopover.hide(); + }); + } + } + + + getDebugConfigLabel(debugSettings: EntityDebugSettings): string { + const isDebugActive = this.isDebugActive(debugSettings?.allEnabledUntil); + + if (!isDebugActive) { + return debugSettings?.failuresEnabled ? this.translate.instant('debug-settings.failures') : this.translate.instant('common.disabled'); + } else { + return this.durationLeft.transform(debugSettings?.allEnabledUntil); + } + } + + isDebugActive(allEnabledUntil: number): boolean { + return allEnabledUntil > new Date().getTime(); + } +} diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index e680232129..76998669fd 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -184,7 +184,6 @@ import { import { EntityChipsComponent } from '@home/components/entity/entity-chips.component'; import { DashboardViewComponent } from '@home/components/dashboard-view/dashboard-view.component'; import { CalculatedFieldsTableComponent } from '@home/components/calculated-fields/calculated-fields-table.component'; -import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { CalculatedFieldDialogComponent } from '@home/components/calculated-fields/components/dialog/calculated-field-dialog.component'; import { EntityDebugSettingsButtonComponent @@ -204,6 +203,7 @@ import { import { CalculatedFieldTestArgumentsComponent } from '@home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component'; +import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @NgModule({ declarations: @@ -504,7 +504,7 @@ import { providers: [ WidgetComponentService, CustomDialogService, - DurationLeftPipe, + EntityDebugSettingsService, {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent}, diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 6fe8cd040e..87536fdc54 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -203,6 +203,17 @@ export interface EntityDebugSettings { allEnabledUntil?: number; } +export interface EntityDebugSettingPanelConfig { + debugSettings: EntityDebugSettings; + debugConfig: { + maxDebugModeDuration: number; + debugLimitsConfiguration: string; + entityLabel?: string; + additionalActionConfig?: AdditionalDebugActionConfig; + } + onSettingsAppliedFn: (settings: EntityDebugSettings) => void; +} + export interface EntityTestScriptResult { output: string; error: string; diff --git a/ui-ngx/src/app/shared/shared.module.ts b/ui-ngx/src/app/shared/shared.module.ts index 7eb622029f..8eec19379e 100644 --- a/ui-ngx/src/app/shared/shared.module.ts +++ b/ui-ngx/src/app/shared/shared.module.ts @@ -225,6 +225,7 @@ import { GroupingIntervalOptionsComponent } from '@shared/components/time/aggreg import { JsFuncModulesComponent } from '@shared/components/js-func-modules.component'; import { JsFuncModuleRowComponent } from '@shared/components/js-func-module-row.component'; import { EntityKeyAutocompleteComponent } from '@shared/components/entity/entity-key-autocomplete.component'; +import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) { return markedOptionsService; @@ -244,6 +245,7 @@ export function MarkedOptionsFactory(markedOptionsService: MarkedOptionsService) ShortNumberPipe, ImagePipe, CustomTranslatePipe, + DurationLeftPipe, { provide: FlowInjectionToken, useValue: Flow From 9d4be3a9b38eed204052eaa29c7617265e84f606 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 16:44:34 +0200 Subject: [PATCH 019/116] optimization --- .../calculated-fields/calculated-fields-table-config.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 9cb04ee04a..ddf52642f0 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -153,13 +153,15 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.openDebugEventsDialog(calculatedField) }; - const { viewContainerRef } = this.getTable(); if ($event) { $event.stopPropagation(); } - this.entityDebugSettingsService.viewContainerRef = viewContainerRef; - this.entityDebugSettingsService.renderer = this.renderer; + const { viewContainerRef, renderer } = this.entityDebugSettingsService; + if (!viewContainerRef || !renderer) { + this.entityDebugSettingsService.viewContainerRef = this.getTable().viewContainerRef; + this.entityDebugSettingsService.renderer = this.renderer; + } this.entityDebugSettingsService.openDebugStrategyPanel({ debugSettings, From c1a70dcbaa6c5e5cf4cad330e26024066f7d5f34 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 16:55:35 +0200 Subject: [PATCH 020/116] optimization --- .../calculated-fields/calculated-fields-table.component.ts | 1 + .../src/app/modules/home/components/home-components.module.ts | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index 82d96b9557..c1dd0bbd5a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -40,6 +40,7 @@ import { EntityDebugSettingsService } from '@home/components/entity/debug/entity templateUrl: './calculated-fields-table.component.html', styleUrls: ['./calculated-fields-table.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, + providers: [EntityDebugSettingsService] }) export class CalculatedFieldsTableComponent { diff --git a/ui-ngx/src/app/modules/home/components/home-components.module.ts b/ui-ngx/src/app/modules/home/components/home-components.module.ts index 76998669fd..ac0296e2a5 100644 --- a/ui-ngx/src/app/modules/home/components/home-components.module.ts +++ b/ui-ngx/src/app/modules/home/components/home-components.module.ts @@ -203,7 +203,6 @@ import { import { CalculatedFieldTestArgumentsComponent } from '@home/components/calculated-fields/components/test-arguments/calculated-field-test-arguments.component'; -import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; @NgModule({ declarations: @@ -504,7 +503,6 @@ import { EntityDebugSettingsService } from '@home/components/entity/debug/entity providers: [ WidgetComponentService, CustomDialogService, - EntityDebugSettingsService, {provide: EMBED_DASHBOARD_DIALOG_TOKEN, useValue: EmbedDashboardDialogComponent}, {provide: COMPLEX_FILTER_PREDICATE_DIALOG_COMPONENT_TOKEN, useValue: ComplexFilterPredicateDialogComponent}, {provide: DASHBOARD_PAGE_COMPONENT_TOKEN, useValue: DashboardPageComponent}, From 977d60bbcbbfd9dca3dd26f14dba0ffe7d5eeb23 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Mon, 3 Mar 2025 17:24:22 +0200 Subject: [PATCH 021/116] Removed provision type --- .../mobile-action-editor.component.html | 21 +------------------ .../action/mobile-action-editor.component.ts | 11 +--------- .../action/mobile-action-editor.models.ts | 6 +++--- .../components/widget/widget.component.ts | 6 ++---- ui-ngx/src/app/shared/models/widget.models.ts | 21 ++----------------- .../assets/locale/locale.constant-en_US.json | 11 +--------- 6 files changed, 10 insertions(+), 66 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html index 84c1dec938..c21595eea9 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html @@ -36,26 +36,7 @@ - -
-
{{ 'widget-action.mobile.provisioning-device.type' | translate }}*
- - - - {{ widgetMobileProvisionTypeTranslationMap.get(mobileProvisionType[actionType]) | translate }} - - - - warning - - -
+ ( - [ - [ WidgetMobileProvisionType.smartConfigEspTouch, 'widget-action.mobile.provisioning-device.smart-config-esp-touch' ], - [ WidgetMobileProvisionType.smartConfigEspTouchV2, 'widget-action.mobile.provisioning-device.smart-config-esp-touch-v2' ], - [ WidgetMobileProvisionType.wifi, 'widget-action.mobile.provisioning-device.wifi' ], - [ WidgetMobileProvisionType.softAp, 'widget-action.mobile.provisioning-device.soft-ap' ] - ] -); - export const widgetActionTypes = Object.keys(WidgetActionType) as WidgetActionType[]; export const widgetActionTypeTranslationMap = new Map( @@ -632,7 +616,7 @@ export const widgetMobileActionTypeTranslationMap = new Map { export interface ProvisionSuccessDescriptor { handleProvisionSuccessFunction: TbFunction; - provisionType: WidgetMobileProvisionType; } export interface ProcessImageDescriptor { diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 7325872f91..9e347adecc 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -6534,16 +6534,7 @@ "URL": "URL", "url-required": "URL is required.", "mobile": { - "provisioning-device": { - "label": "Provisioning device", - "type": "Provisioning device type", - "select-type": "Select provisioning device type", - "type-required": "Provisioning device type is required", - "smart-config-esp-touch": "Smart Config ESP-Touch", - "smart-config-esp-touch-v2": "Smart Config ESP-Touch v2", - "wifi": "Wi-Fi Provisioning via Bluetooth Low Energy BLE/QR code", - "soft-ap": "SoftAP" - }, + "provision-device": "Provision device", "action-type": "Mobile action type", "select-action-type": "Select mobile action type", "action-type-required": "Mobile action type is required", From 864802fa6bc90b2ef6019a35d3309ff0d9ecfe3c Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 4 Mar 2025 11:26:04 +0200 Subject: [PATCH 022/116] UI: Format for tank scale --- .../system/scada_symbols/cylindrical-tank.svg | 219 ++++++----------- .../system/scada_symbols/elevated-tank.svg | 219 ++++++----------- .../scada_symbols/horizontal-tank-hp.svg | 140 +++++------ .../system/scada_symbols/horizontal-tank.svg | 219 ++++++----------- .../scada_symbols/large-cylindrical-tank.svg | 219 ++++++----------- .../large-stand-cylindrical-tank.svg | 217 ++++++----------- .../large-stand-vertical-tank.svg | 219 ++++++----------- .../scada_symbols/large-vertical-tank.svg | 219 ++++++----------- .../json/system/scada_symbols/pool-hp.svg | 140 +++++------ .../scada_symbols/short-vertical-tank-hp.svg | 140 +++++------ .../scada_symbols/small-cylindrical-tank.svg | 219 ++++++----------- .../scada_symbols/small-spherical-tank.svg | 219 ++++++----------- .../system/scada_symbols/spherical-tank.svg | 219 ++++++----------- .../scada_symbols/stand-cylindrical-tank.svg | 219 ++++++----------- .../scada_symbols/stand-horizontal-tank.svg | 219 ++++++----------- .../stand-vertical-short-tank.svg | 219 ++++++----------- .../scada_symbols/stand-vertical-tank.svg | 217 ++++++----------- .../scada_symbols/vertical-short-tank.svg | 220 ++++++------------ .../system/scada_symbols/vertical-tank-hp.svg | 140 +++++------ .../system/scada_symbols/vertical-tank.svg | 220 ++++++------------ .../assets/locale/locale.constant-en_US.json | 1 + 21 files changed, 1295 insertions(+), 2768 deletions(-) diff --git a/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg index 513809cca5..ab0b5415bd 100644 --- a/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg @@ -33,7 +33,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -278,80 +278,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextFont", @@ -364,80 +327,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -450,128 +411,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/elevated-tank.svg b/application/src/main/data/json/system/scada_symbols/elevated-tank.svg index 9db211457e..7019e3221a 100644 --- a/application/src/main/data/json/system/scada_symbols/elevated-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/elevated-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 265;\n var majorIntervalLength = 895 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(825, y, 857, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 815, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(837, minorY, 857, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 265;\n var majorIntervalLength = 895 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(825, y, 857, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 815, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(837, minorY, 857, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -274,80 +274,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -360,80 +323,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "transparent", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -446,128 +407,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg index cff6a97eb9..2adde5881f 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg @@ -38,7 +38,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 592 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(208, y, 240, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 198, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 198, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 198, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(220, minorY, 240, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 592 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(208, y, 240, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 198, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 198, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 198, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(220, minorY, 240, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -307,64 +307,67 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#EBEBEB", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#C8DFF7", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": false, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -377,96 +380,57 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks}", "type": "color", "default": "#00000061", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks}", "type": "color", "default": "#0000001F", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "warningColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "criticalColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg b/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg index 7875b5dde0..f410d709f4 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg @@ -33,7 +33,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 17;\n var majorIntervalLength = 568 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(715, y, 747, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 705, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(727, minorY, 747, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 17;\n var majorIntervalLength = 568 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(715, y, 747, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 705, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(727, minorY, 747, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -278,80 +278,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -364,80 +327,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -450,128 +411,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg index 772e34f0f7..98f61f0094 100644 --- a/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg @@ -33,7 +33,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 60;\n var majorIntervalLength = 910 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(656, y, 688, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 646, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(668, minorY, 688, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 60;\n var majorIntervalLength = 910 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(656, y, 688, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 646, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(668, minorY, 688, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -278,80 +278,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -364,80 +327,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -450,128 +411,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg index dc9cb47268..ac94438463 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 60;\n var majorIntervalLength = 910 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(656, y, 688, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 646, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(668, minorY, 688, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 60;\n var majorIntervalLength = 910 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(656, y, 688, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 646, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(668, minorY, 688, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,76 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ] }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +410,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg index b7cb67f2a0..5b534b615c 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 203;\n var majorIntervalLength = 763 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(676, y, 708, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 666, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(688, minorY, 708, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 203;\n var majorIntervalLength = 763 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(676, y, 708, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 666, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(688, minorY, 708, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg index 3b9420e04d..33bd6c2f39 100644 --- a/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg @@ -33,7 +33,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 203;\n var majorIntervalLength = 763 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(676, y, 708, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 666, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(688, minorY, 708, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 203;\n var majorIntervalLength = 763 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(676, y, 708, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 666, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(688, minorY, 708, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -278,80 +278,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -364,80 +327,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -450,128 +411,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/pool-hp.svg b/application/src/main/data/json/system/scada_symbols/pool-hp.svg index 357563a687..74757b77d6 100644 --- a/application/src/main/data/json/system/scada_symbols/pool-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/pool-hp.svg @@ -38,7 +38,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 792 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(298, y, 330, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 288, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 288, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 288, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(310, minorY, 330, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 792 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(298, y, 330, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 288, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 288, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 288, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(310, minorY, 330, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -307,64 +307,57 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#EBEBEB", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#C8DFF7", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": false, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -377,96 +370,67 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks}", "type": "color", "default": "#00000061", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks}", "type": "color", "default": "#0000001F", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "warningColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "criticalColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg index 1f635fc810..1ce12cafe2 100644 --- a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg @@ -38,7 +38,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 594 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(170, y, 202, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 160, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 160, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 160, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(182, minorY, 202, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 594 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(170, y, 202, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 160, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 160, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 160, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(182, minorY, 202, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -307,64 +307,67 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#EBEBEB", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#C8DFF7", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": false, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -377,96 +380,57 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks}", "type": "color", "default": "#00000061", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks}", "type": "color", "default": "#0000001F", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "warningColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "criticalColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg index 85bad5d9e0..9af2be50c4 100644 --- a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 45;\n var majorIntervalLength = 525 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 45;\n var majorIntervalLength = 525 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg b/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg index 7e6e4fa8a6..e0b50e3200 100644 --- a/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 23;\n var majorIntervalLength = 560 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(268, y, 300, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 258, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(280, minorY, 300, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 23;\n var majorIntervalLength = 560 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(268, y, 300, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 258, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(280, minorY, 300, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg index 4184bcf593..11698d6636 100644 --- a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 23;\n var majorIntervalLength = 960 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(458, y, 490, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 448, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(470, minorY, 490, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 23;\n var majorIntervalLength = 960 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(458, y, 490, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 448, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(470, minorY, 490, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": true, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg index 2ad4ac9ec8..9ee0eb5122 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg index 8c3745ec3d..5ec5f34b8f 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 17;\n var majorIntervalLength = 568 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(715, y, 747, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 705, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(727, minorY, 747, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 17;\n var majorIntervalLength = 568 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(715, y, 747, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 705, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(727, minorY, 747, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg index 43eac50d35..a92ba1e274 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg @@ -35,7 +35,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 137;\n var majorIntervalLength = 442 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(523, y, 555, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 513, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(535, minorY, 555, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 137;\n var majorIntervalLength = 442 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(523, y, 555, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 513, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(535, minorY, 555, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -280,80 +280,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -366,80 +329,78 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -452,128 +413,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg index 07c3ea050c..1b19157341 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,76 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ] }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +410,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg b/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg index d4358e8fa7..23fe4a2733 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg @@ -34,7 +34,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 137;\n var majorIntervalLength = 442 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(523, y, 555, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 513, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(535, minorY, 555, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 137;\n var majorIntervalLength = 442 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(523, y, 555, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 513, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(535, minorY, 555, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -279,80 +279,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -365,80 +328,79 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "required": false, + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -451,128 +413,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg index 3e29a4e657..e1b57d7906 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg @@ -38,7 +38,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 994 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(160, y, 192, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 150, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 150, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 150, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(172, minorY, 192, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 3;\n var majorIntervalLength = 994 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(160, y, 192, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n if (i === 0) {\n majorTickText.attr({x: 150, y: y + 10, 'text-anchor': 'end', class: 'majorTickText'});\n } else if (i === majorIntervals) {\n majorTickText.attr({x: 150, y: y - 5, 'text-anchor': 'end', class: 'majorTickText'});\n } else {\n majorTickText.attr({x: 150, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n }\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(172, minorY, 192, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -307,64 +307,67 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#EBEBEB", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#C8DFF7", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": false, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -377,96 +380,57 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks}", "type": "color", "default": "#00000061", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks}", "type": "color", "default": "#0000001F", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "warningColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "criticalColor", "name": "{i18n:scada.symbol.alarm-colors}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/application/src/main/data/json/system/scada_symbols/vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/vertical-tank.svg index de7f907e76..868256e3df 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-tank.svg @@ -33,7 +33,7 @@ }, { "tag": "scale", - "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = (100 - i * (100/majorIntervals)).toFixed(0);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", + "stateRenderFunction": "if (!ctx.properties.scale) {\n element.hide();\n} else {\n var scaleSet = element.remember('scaleSet');\n if (!scaleSet) {\n element.remember('scaleSet', true);\n element.clear();\n \n var majorIntervals = ctx.properties.majorIntervals;\n var minorIntervals = ctx.properties.minorIntervals;\n \n var start = 205;\n var majorIntervalLength = 760 / majorIntervals;\n var minorIntervalLength = majorIntervalLength / minorIntervals;\n var tankCapacity = ctx.properties.scaleDisplayFormat ? 100 : (ctx.values.tankCapacity || 100);\n for (var i = 0; i < majorIntervals + 1; i++) {\n var y = start + i * majorIntervalLength;\n var line = ctx.svg.line(340, y, 372, y).stroke({ width: 3 }).attr({class: 'majorTick'});\n element.add(line);\n var majorText = ctx.api.formatValue((tankCapacity - i * (tankCapacity/majorIntervals)).toFixed(0), 0, ctx.properties.majorUnits, false);\n var majorTickText = ctx.svg.text(majorText);\n majorTickText.attr({x: 330, y: y + 2, 'text-anchor': 'end', class: 'majorTickText'});\n majorTickText.first().attr({'dominant-baseline': 'middle'});\n element.add(majorTickText);\n if (i < majorIntervals) {\n drawMinorTicks(y, minorIntervals, minorIntervalLength);\n }\n }\n }\n \n var majorFont = ctx.properties.majorFont;\n var majorColor = ctx.properties.majorColor;\n var minorColor = ctx.properties.minorColor;\n if (ctx.values.critical) {\n majorColor = ctx.properties.majorCriticalColor;\n minorColor = ctx.properties.minorCriticalColor;\n } else if (ctx.values.warning) {\n majorColor = ctx.properties.minorWarningColor;\n minorColor = ctx.properties.minorWarningColor;\n }\n \n var majorTicks = element.find('line.majorTick');\n majorTicks.forEach(t => t.attr({stroke: majorColor}));\n \n var majorTicksText = element.find('text.majorTickText');\n ctx.api.font(majorTicksText, majorFont, majorColor);\n \n var minorTicks = element.find('line.minorTick');\n minorTicks.forEach(t => t.attr({stroke: minorColor}));\n \n var elementCriticalAnimation = element.remember('criticalAnimation');\n var criticalAnimation = ctx.values.critical && ctx.values.criticalAnimation;\n\n if (elementCriticalAnimation !== criticalAnimation) {\n element.remember('criticalAnimation', criticalAnimation);\n if (criticalAnimation) {\n ctx.api.cssAnimate(element, 500).attr({opacity: 0.15}).loop(0, true);\n } else {\n ctx.api.resetCssAnimation(element);\n }\n }\n}\n\nfunction drawMinorTicks(start, minorIntervals, minorIntervalLength) {\n for (var i = 1; i < minorIntervals; i++) {\n var minorY = start + i * minorIntervalLength;\n var minorLine = ctx.svg.line(352, minorY, 372, minorY).stroke({ width: 3 }).attr({class: 'minorTick'});\n element.add(minorLine);\n }\n}", "actions": null }, { @@ -278,80 +278,43 @@ "name": "{i18n:scada.symbol.tank-color}", "type": "color", "default": "#E5E5E5", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "fluidColor", "name": "{i18n:scada.symbol.fluid-color}", "type": "color", "default": "#1EC1F480", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBox", "name": "{i18n:scada.symbol.value-box}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueBoxColor", "name": "{i18n:scada.symbol.value-box}", "type": "color", "default": "#F3F3F3", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueUnits", "name": "{i18n:scada.symbol.value-text}", "type": "units", "default": "gal", - "required": null, "subLabel": "{i18n:scada.symbol.units}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextFont", @@ -364,80 +327,79 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "valueTextColor", "name": "{i18n:scada.symbol.value-text}", "type": "color", "default": "#0000008A", - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "valueBox", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "scale", "name": "{i18n:scada.symbol.scale}", "type": "switch", "default": true, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, - "disableOnProperty": null, - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true + }, + { + "id": "scaleDisplayFormat", + "name": "{i18n:scada.symbol.scale}", + "type": "select", + "default": true, + "subLabel": "{i18n:scada.symbol.display-format}", + "divider": false, + "disableOnProperty": "scale", + "items": [ + { + "value": true, + "label": "Percentage" + }, + { + "value": false, + "label": "Metric" + } + ], + "disabled": false, + "visible": true }, { "id": "transparent", "name": "{i18n:scada.symbol.transparent-mode}", "type": "switch", "default": false, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorIntervals", "name": "{i18n:scada.symbol.major-ticks}", "type": "number", "default": 10, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": 1 + "step": 1, + "disabled": false, + "visible": true + }, + { + "id": "majorUnits", + "name": "{i18n:scada.symbol.major-ticks}", + "type": "units", + "subLabel": "{i18n:scada.symbol.units}", + "divider": true, + "disableOnProperty": "scale", + "disabled": false, + "visible": true }, { "id": "majorFont", @@ -450,128 +412,84 @@ "weight": "500", "style": "normal" }, - "required": null, - "subLabel": null, - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#00000061", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorWarningColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "majorCriticalColor", "name": "{i18n:scada.symbol.major-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorIntervals", "name": "{i18n:scada.symbol.minor-ticks}", "type": "number", "default": 5, - "required": null, "subLabel": "{i18n:scada.symbol.intervals}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", "min": 1, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#0000001F", - "required": null, "subLabel": "{i18n:scada.symbol.normal}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorWarningColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#FAA405", - "required": null, "subLabel": "{i18n:scada.symbol.warning}", "divider": true, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true }, { "id": "minorCriticalColor", "name": "{i18n:scada.symbol.minor-ticks-color}", "type": "color", "default": "#D12730", - "required": null, "subLabel": "{i18n:scada.symbol.critical}", - "divider": null, - "fieldSuffix": null, "disableOnProperty": "scale", - "rowClass": "", - "fieldClass": "", - "min": null, - "max": null, - "step": null + "disabled": false, + "visible": true } ] }]]> diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index de97184f5a..ba7683c30e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -3217,6 +3217,7 @@ "top-fluid-color": "Top fluid color", "bottom-fluid-color": "Bottom fluid color", "display": "Display", + "display-format": "Display format", "value": "Value", "decimals": "Decimals", "units": "Units", From 8d4c90b389aeb697987928262f0c0dc265115018 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 4 Mar 2025 12:29:23 +0200 Subject: [PATCH 023/116] Changed device to deviceName --- .../src/app/modules/home/components/widget/widget.component.ts | 2 +- ui-ngx/src/app/shared/models/widget.models.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index bb41315c5c..ca11c2f4e0 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1294,7 +1294,7 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, } break; case WidgetMobileActionType.provisionDevice: - const deviceName = actionResult.device.name; + const deviceName = actionResult.deviceName; if (isNotEmptyTbFunction(mobileAction.handleProvisionSuccessFunction)) { compileTbFunction(this.http, mobileAction.handleProvisionSuccessFunction, 'deviceName', '$event', 'widgetContext', 'entityId', 'entityName', 'additionalParams', 'entityLabel').subscribe( diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index db88ba0283..132c82cfd1 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -639,7 +639,7 @@ export interface MobileLocationResult { } export interface MobileDeviceProvisioningResult { - device: Device; + deviceName: string; } export type MobileActionResult = MobileLaunchResult & From 4cb5072ac6531ed9f84a9e0dfba35f4a6bd4bc62 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 4 Mar 2025 13:54:15 +0200 Subject: [PATCH 024/116] Reworked provision to toasts --- .../common/action/mobile-action-editor.models.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts index 5164b6c8b8..54e70dc34b 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.models.ts @@ -140,10 +140,12 @@ const processLocationFunction: TbFunction = const provisioningSuccessFunction: TbFunction = '// Function body to handle device provision success. \n' + - '// - device - device that was successfully provisioned.\n' + - 'function showDeviceProvisioningSuccess(deviceName, message) {\n' + + '// - deviceName - name of device that was successfully provisioned.\n' + + 'showDeviceProvisioningSuccess(deviceName);\n' + + '\n' + + 'function showDeviceProvisioningSuccess(deviceName) {\n' + ' setTimeout(function() {\n' + - ' widgetContext.dialogs.alert(`Device ` + deviceName + ` was successfully provisioned`, message).subscribe();\n' + + ' widgetContext.showSuccessToast(`Device ` + deviceName + ` was successfully provisioned`).subscribe();\n' + ' }, 100);\n' + '}\n'; @@ -154,7 +156,7 @@ const handleEmptyResultFunctionTemplate: TbFunction = '\n' + 'function showEmptyResultDialog(message) {\n' + ' setTimeout(function() {\n' + - ' widgetContext.dialogs.alert(\'Empty result\', message).subscribe();\n' + + ' widgetContext.showInfoToast(message).subscribe();\n' + ' }, 100);\n' + '}\n'; From 705a5742d0142be67b63a355726dc1ad9fccbbb9 Mon Sep 17 00:00:00 2001 From: trikimiki <41070061+trikimiki@users.noreply.github.com> Date: Tue, 4 Mar 2025 17:27:12 +0200 Subject: [PATCH 025/116] add exitcode for check folder script --- docker/docker-check-log-folders.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docker/docker-check-log-folders.sh b/docker/docker-check-log-folders.sh index 22e91ea3f3..6122f3d2c1 100755 --- a/docker/docker-check-log-folders.sh +++ b/docker/docker-check-log-folders.sh @@ -21,6 +21,8 @@ if checkFolders "$@" ; then echo "------" echo "All checks have passed" else + CHECK_EXIT_CODE=$? echo "------" echo "Some checks did not pass - check the output" + exit $CHECK_EXIT_CODE fi \ No newline at end of file From bbedb8797b6234e3bf0ef146dd8b48e277e9cdeb Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 7 Mar 2025 11:09:39 +0200 Subject: [PATCH 026/116] UI: Widget header button action --- .../widget-action-dialog.component.html | 74 +++++++++++++++-- .../action/widget-action-dialog.component.ts | 44 ++++++++++ .../widget/widget-container.component.html | 81 +++++++++++++++++-- .../widget/widget-container.component.scss | 2 +- .../widget/widget-container.component.ts | 5 +- .../components/widget/widget.component.ts | 6 ++ .../home/models/widget-component.models.ts | 7 ++ ui-ngx/src/app/shared/models/widget.models.ts | 41 ++++++++++ .../assets/locale/locale.constant-en_US.json | 16 ++++ 9 files changed, 260 insertions(+), 16 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html index ec1b165401..3e9bc581e1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.html @@ -88,12 +88,74 @@ -
-
{{'widget-config.icon' | translate}}
- - -
+ @if (widgetActionFormGroup.get('actionSourceId').value === 'headerButton') { +
+
widget-config.header-button.button-settings
+
+
widget-config.header-button.button-type
+ + + + {{ widgetHeaderActionButtonTypeTranslationMap.get(widgetHeaderActionButtonType[button]) | translate }} + + + +
+
+
+ + +
widget-config.icon
+
+ + +
+
+
{{ 'widget-config.header-button.colors' | translate }}
+
+
widget-config.header-button.color
+ + + +
widget-config.header-button.background
+ + + +
widget-config.header-button.border
+ + +
+
+
+ + + + widget-config.header-button.advanced-button-style + + + + + + +
+
+ } @else { +
+
{{'widget-config.icon' | translate}}
+ + +
+ } +
diff --git a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts index df8df4a882..a04609b241 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts @@ -43,6 +43,10 @@ import { CellClickColumnInfo, defaultWidgetAction, WidgetActionSource, + WidgetHeaderActionButtonType, + widgetHeaderActionButtonTypeMap, + WidgetHeaderActionButtonTypes, + widgetHeaderActionButtonTypeTranslationMap, widgetType } from '@shared/models/widget.models'; import { takeUntil } from 'rxjs/operators'; @@ -85,6 +89,11 @@ export class WidgetActionDialogComponent extends DialogComponent = []; usedCellClickColumns: Array = []; + widgetHeaderActionButtonType = WidgetHeaderActionButtonType + widgetHeaderActionButtonTypes = WidgetHeaderActionButtonTypes; + widgetHeaderActionButtonTypeTranslationMap = widgetHeaderActionButtonTypeTranslationMap; + widgetHeaderActionButtonTypeMap = widgetHeaderActionButtonTypeMap; + @ViewChild('columnIndexSelect') columnIndexSelect: MatSelect; columnIndexPlaceholderText = this.translate.instant('widget-config.select-column-index'); @@ -120,12 +129,19 @@ export class WidgetActionDialogComponent extends DialogComponent { @@ -143,6 +159,9 @@ export class WidgetActionDialogComponent extends DialogComponent { this.updateShowWidgetActionForm(); }); + this.widgetActionFormGroup.get('buttonType').valueChanges.pipe( + takeUntil(this.destroy$) + ).subscribe(() => this.widgetHeaderButtonValidators()); setTimeout(() => { if (this.action?.actionSourceId === 'cellClick') { this.widgetActionFormGroup.get('columnIndex').enable(); @@ -160,6 +179,31 @@ export class WidgetActionDialogComponent extends DialogComponent - +
+ + @switch (action.buttonType) { + @case (widgetHeaderActionButtonType.icon) { + + } + @case (widgetHeaderActionButtonType.miniFab) { + + } + @case (widgetHeaderActionButtonType.basic) { + + } + @case (widgetHeaderActionButtonType.raised) { + + } + @case (widgetHeaderActionButtonType.stroked) { + + } + @case (widgetHeaderActionButtonType.flat) { + + } + } + +
+ - } - @case (widgetHeaderActionButtonType.miniFab) { - - } - @case (widgetHeaderActionButtonType.basic) { - - } - @case (widgetHeaderActionButtonType.raised) { - - } - @case (widgetHeaderActionButtonType.stroked) { - - } - @case (widgetHeaderActionButtonType.flat) { - - } - } - +
+ @for (action of widget.customHeaderActions; track action.name; let last = $last) { + + }
+ + +@switch (action.buttonType) { + @case (widgetHeaderActionButtonType.icon) { + + } + @case (widgetHeaderActionButtonType.miniFab) { + + } + @case (widgetHeaderActionButtonType.basic) { + + } + @case (widgetHeaderActionButtonType.raised) { + + } + @case (widgetHeaderActionButtonType.stroked) { + + } + @case (widgetHeaderActionButtonType.flat) { + + } +} + diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss index d763c11c9e..b246bc1662 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.scss @@ -86,8 +86,8 @@ div.tb-widget { flex-direction: row; place-content: center flex-start; align-items: center; - z-index: 19; - margin: 5px 0 5px; + z-index: 101; + margin: 5px 0 0; &-absolute { position: absolute; From ca350601bb47853738d9280fb21bd12e821e08ed Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 7 Mar 2025 14:46:25 +0200 Subject: [PATCH 030/116] Resolved conflicts --- .../calculated-fields/calculated-fields-table.component.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts index 91a4d69252..e10c4b301e 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table.component.ts @@ -58,8 +58,6 @@ export class CalculatedFieldsTableComponent { private dialog: MatDialog, private store: Store, private datePipe: DatePipe, - private durationLeft: DurationLeftPipe, - private popoverService: TbPopoverService, private cd: ChangeDetectorRef, private renderer: Renderer2, private importExportService: ImportExportService, From 04c7160e73223e64897b2d93c19f98393ad0d3ab Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 7 Mar 2025 15:01:40 +0200 Subject: [PATCH 031/116] UI: Refactoring --- .../widget/action/widget-action-dialog.component.ts | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts index b921c89c52..b439a5771f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/action/widget-action-dialog.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, DestroyRef, Inject, OnDestroy, OnInit, SkipSelf, ViewChild } from '@angular/core'; +import { Component, DestroyRef, Inject, OnInit, SkipSelf, ViewChild } from '@angular/core'; import { ErrorStateMatcher } from '@angular/material/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; @@ -69,7 +69,7 @@ export interface WidgetActionDialogData { styleUrls: [] }) export class WidgetActionDialogComponent extends DialogComponent implements OnInit, OnDestroy, ErrorStateMatcher { + WidgetActionDescriptorInfo> implements OnInit, ErrorStateMatcher { widgetActionFormGroup: FormGroup; @@ -169,10 +169,6 @@ export class WidgetActionDialogComponent extends DialogComponent Date: Fri, 7 Mar 2025 15:12:24 +0200 Subject: [PATCH 032/116] Implemented tbel utils autocompletes and highlights --- .../shared/components/js-func.component.scss | 6 + .../shared/components/js-func.component.ts | 7 + .../shared/models/ace/tbel-utils.models.ts | 1287 +++++++++++++++++ 3 files changed, 1300 insertions(+) create mode 100644 ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts diff --git a/ui-ngx/src/app/shared/components/js-func.component.scss b/ui-ngx/src/app/shared/components/js-func.component.scss index eecfe72c3e..12b1d57ccc 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.scss +++ b/ui-ngx/src/app/shared/components/js-func.component.scss @@ -79,4 +79,10 @@ background: #f3f3f3; } } + + .ace_tb { + &.ace_tbel-utils-func { + color: #0000A2; + } + } } diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index eccb5cb908..682cc872e6 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -50,6 +50,7 @@ import { JsFuncModulesComponent } from '@shared/components/js-func-modules.compo import { HttpClient } from '@angular/common/http'; import { map, Observable, of } from 'rxjs'; import { catchError } from 'rxjs/operators'; +import { tbelUtilsAutocompletes, tbelUtilsFuncHighlightRules } from '@shared/models/ace/tbel-utils.models'; @Component({ selector: 'tb-js-func', @@ -587,6 +588,9 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal newMode.$highlightRules.$rules[group] = this.highlightRules[group]; } } + if (this.scriptLanguage === ScriptLanguage.TBEL) { + newMode.$highlightRules.$rules.start = [...tbelUtilsFuncHighlightRules, ...newMode.$highlightRules.$rules.start]; + } const identifierRule = newMode.$highlightRules.$rules.no_regex.find(rule => rule.token?.includes('identifier')); if (identifierRule) { identifierRule.next = 'start'; @@ -641,6 +645,9 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal if (modulesCompleter) { completers.push(modulesCompleter); } + if (this.scriptLanguage === ScriptLanguage.TBEL) { + completers.push(tbelUtilsAutocompletes); + } completers.push(...this.initialCompleters); this.jsEditor.completers = completers; }); diff --git a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts new file mode 100644 index 0000000000..24b6d9eaaf --- /dev/null +++ b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts @@ -0,0 +1,1287 @@ +import { AceHighlightRule } from '@shared/models/ace/ace.models'; +import { TbEditorCompleter } from '@shared/models/ace/completion.models'; + +export const tbelUtilsAutocompletes = new TbEditorCompleter({ + btoa: { + meta: 'function', + description: 'Encodes a string to Base64.', + args: [ + { + name: 'input', + description: 'The string to encode', + type: 'string' + } + ], + return: { + description: 'The Base64 encoded string', + type: 'string' + } + }, + atob: { + meta: 'function', + description: 'Decodes a Base64 encoded string.', + args: [ + { + name: 'encoded', + description: 'The Base64 encoded string to decode', + type: 'string' + } + ], + return: { + description: 'The decoded string', + type: 'string' + } + }, + bytesToString: { + meta: 'function', + description: 'Converts a list of bytes to a string, optionally specifying the charset.', + args: [ + { + name: 'bytesList', + description: 'The list of bytes to convert', + type: 'array' + }, + { + name: 'charsetName', + description: 'The charset to use for conversion (e.g., "UTF-8")', + type: 'string', + optional: true + } + ], + return: { + description: 'The string representation of the bytes', + type: 'string' + } + }, + decodeToString: { + meta: 'function', + description: 'Converts a list of bytes to a string using the default charset.', + args: [ + { + name: 'bytesList', + description: 'The list of bytes to convert', + type: 'array' + } + ], + return: { + description: 'The string representation of the bytes', + type: 'string' + } + }, + decodeToJson: { + meta: 'function', + description: 'Parses a JSON string or converts a list of bytes to a string and parses it as JSON.', + args: [ + { + name: 'input', + description: 'The JSON string or list of bytes to parse', + type: 'string | array' + } + ], + return: { + description: 'The parsed JSON object (e.g., object, array, or primitive)', + type: 'object' + } + }, + stringToBytes: { + meta: 'function', + description: 'Converts a string to a list of bytes, optionally specifying the charset.', + args: [ + { + name: 'str', + description: 'The string to convert', + type: 'string' + }, + { + name: 'charsetName', + description: 'The charset to use for conversion (e.g., "UTF-8")', + type: 'string', + optional: true + } + ], + return: { + description: 'The list of bytes representing the string', + type: 'array' + } + }, + parseInt: { + meta: 'function', + description: 'Parses a string to an integer, optionally specifying the radix.', + args: [ + { + name: 'value', + description: 'The string to parse', + type: 'string' + }, + { + name: 'radix', + description: 'The radix for parsing (e.g., 2 for binary, 16 for hex, defaults to auto-detection if 0)', + type: 'number', + optional: true + } + ], + return: { + description: 'The parsed integer, or null if invalid', + type: 'number' + } + }, + parseLong: { + meta: 'function', + description: 'Parses a string to a long integer, optionally specifying the radix.', + args: [ + { + name: 'value', + description: 'The string to parse', + type: 'string' + }, + { + name: 'radix', + description: 'The radix for parsing (e.g., 2 for binary, 16 for hex, defaults to auto-detection if 0)', + type: 'number', + optional: true + } + ], + return: { + description: 'The parsed long integer, or null if invalid', + type: 'number' + } + }, + parseFloat: { + meta: 'function', + description: 'Parses a string to a float. If radix is 16, interprets the string as hexadecimal IEEE 754 float bits.', + args: [ + { + name: 'value', + description: 'The string to parse', + type: 'string' + }, + { + name: 'radix', + description: 'The radix for parsing (e.g., 16 for hex, defaults to 10 if 0)', + type: 'number', + optional: true + } + ], + return: { + description: 'The parsed float, or null if invalid', + type: 'number' + } + }, + parseHexIntLongToFloat: { + meta: 'function', + description: 'Parses a hexadecimal string to a float, treating it as an integer value.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to parse (e.g., "0x0A" for 10.0)', + type: 'string' + }, + { + name: 'bigEndian', + description: 'Whether to interpret the string in big-endian order', + type: 'boolean' + } + ], + return: { + description: 'The parsed float, or null if invalid', + type: 'number' + } + }, + parseDouble: { + meta: 'function', + description: 'Parses a string to a double. If radix is 16, interprets the string as hexadecimal IEEE 754 double bits.', + args: [ + { + name: 'value', + description: 'The string to parse', + type: 'string' + }, + { + name: 'radix', + description: 'The radix for parsing (e.g., 16 for hex, defaults to 10 if unspecified)', + type: 'number', + optional: true + } + ], + return: { + description: 'The parsed double, or null if invalid', + type: 'number' + } + }, + parseLittleEndianHexToInt: { + meta: 'function', + description: 'Parses a little-endian hexadecimal string to an integer.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed integer', + type: 'number' + } + }, + parseBigEndianHexToInt: { + meta: 'function', + description: 'Parses a big-endian hexadecimal string to an integer.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed integer', + type: 'number' + } + }, + parseHexToInt: { + meta: 'function', + description: 'Parses a hexadecimal string to an integer, optionally specifying endianness.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to parse', + type: 'string' + }, + { + name: 'bigEndian', + description: 'Whether to interpret the string in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed integer', + type: 'number' + } + }, + parseBytesToInt: { + meta: 'function', + description: 'Parses a list or array of bytes to an integer.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 4)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed integer', + type: 'number' + } + }, + parseLittleEndianHexToLong: { + meta: 'function', + description: 'Parses a little-endian hexadecimal string to a long integer.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed long integer', + type: 'number' + } + }, + parseBigEndianHexToLong: { + meta: 'function', + description: 'Parses a big-endian hexadecimal string to a long integer.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed long integer', + type: 'number' + } + }, + parseHexToLong: { + meta: 'function', + description: 'Parses a hexadecimal string to a long integer, optionally specifying endianness.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to parse', + type: 'string' + }, + { + name: 'bigEndian', + description: 'Whether to interpret the string in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed long integer', + type: 'number' + } + }, + parseBytesToLong: { + meta: 'function', + description: 'Parses a list or array of bytes to a long integer.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 8)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed long integer', + type: 'number' + } + }, + parseLittleEndianHexToFloat: { + meta: 'function', + description: 'Parses a little-endian hexadecimal string to a float using IEEE 754 format.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed float', + type: 'number' + } + }, + parseBigEndianHexToFloat: { + meta: 'function', + description: 'Parses a big-endian hexadecimal string to a float using IEEE 754 format.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed float', + type: 'number' + } + }, + parseHexToFloat: { + meta: 'function', + description: 'Parses a hexadecimal string to a float using IEEE 754 format, optionally specifying endianness.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to parse', + type: 'string' + }, + { + name: 'bigEndian', + description: 'Whether to interpret the string in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed float', + type: 'number' + } + }, + parseBytesToFloat: { + meta: 'function', + description: 'Parses a list or array of bytes to a float using IEEE 754 format.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 4)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed float', + type: 'number' + } + }, + parseBytesIntToFloat: { + meta: 'function', + description: 'Parses a list or array of bytes to a float by first interpreting them as an integer.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 4)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed float', + type: 'number' + } + }, + parseLittleEndianHexToDouble: { + meta: 'function', + description: 'Parses a little-endian hexadecimal string to a double using IEEE 754 format.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed double', + type: 'number' + } + }, + parseBigEndianHexToDouble: { + meta: 'function', + description: 'Parses a big-endian hexadecimal string to a double using IEEE 754 format.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to parse', + type: 'string' + } + ], + return: { + description: 'The parsed double', + type: 'number' + } + }, + parseHexToDouble: { + meta: 'function', + description: 'Parses a hexadecimal string to a double using IEEE 754 format, optionally specifying endianness.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to parse', + type: 'string' + }, + { + name: 'bigEndian', + description: 'Whether to interpret the string in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed double', + type: 'number' + } + }, + parseBytesToDouble: { + meta: 'function', + description: 'Parses a list or array of bytes to a double using IEEE 754 format.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 8)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed double', + type: 'number' + } + }, + parseBytesLongToDouble: { + meta: 'function', + description: 'Parses a list or array of bytes to a double by first interpreting them as a long integer.', + args: [ + { + name: 'data', + description: 'The bytes to parse', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the byte array', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bytes to parse (max 8)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to interpret bytes in big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The parsed double', + type: 'number' + } + }, + toFixed: { + meta: 'function', + description: 'Rounds a number to a specified number of decimal places.', + args: [ + { + name: 'value', + description: 'The number to round', + type: 'number' + }, + { + name: 'precision', + description: 'The number of decimal places', + type: 'number' + } + ], + return: { + description: 'The rounded number', + type: 'number' + } + }, + toInt: { + meta: 'function', + description: 'Converts a double to an integer by rounding.', + args: [ + { + name: 'value', + description: 'The double to convert', + type: 'number' + } + ], + return: { + description: 'The rounded integer', + type: 'number' + } + }, + hexToBytes: { + meta: 'function', + description: 'Converts a hexadecimal string to a list of bytes.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to convert', + type: 'string' + } + ], + return: { + description: 'The list of bytes', + type: 'array' + } + }, + hexToBytesArray: { + meta: 'function', + description: 'Converts a hexadecimal string to an array of bytes.', + args: [ + { + name: 'value', + description: 'The hexadecimal string to convert', + type: 'string' + } + ], + return: { + description: 'The array of bytes', + type: 'array' + } + }, + intToHex: { + meta: 'function', + description: 'Converts an integer to a hexadecimal string.', + args: [ + { + name: 'i', + description: 'The integer to convert', + type: 'number' + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order (defaults to true)', + type: 'boolean', + optional: true + }, + { + name: 'pref', + description: 'Whether to prefix with "0x" (defaults to false)', + type: 'boolean', + optional: true + }, + { + name: 'len', + description: 'The desired length of the hex string (defaults to minimum required)', + type: 'number', + optional: true + } + ], + return: { + description: 'The hexadecimal string', + type: 'string' + } + }, + longToHex: { + meta: 'function', + description: 'Converts a long integer to a hexadecimal string.', + args: [ + { + name: 'l', + description: 'The long integer to convert', + type: 'number' + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order (defaults to true)', + type: 'boolean', + optional: true + }, + { + name: 'pref', + description: 'Whether to prefix with "0x" (defaults to false)', + type: 'boolean', + optional: true + }, + { + name: 'len', + description: 'The desired length of the hex string (defaults to minimum required)', + type: 'number', + optional: true + } + ], + return: { + description: 'The hexadecimal string', + type: 'string' + } + }, + intLongToRadixString: { + meta: 'function', + description: 'Converts a long integer to a string in the specified radix.', + args: [ + { + name: 'number', + description: 'The number to convert', + type: 'number' + }, + { + name: 'radix', + description: 'The radix for conversion (e.g., 2, 8, 10, 16, defaults to 10)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order for hex (defaults to true)', + type: 'boolean', + optional: true + }, + { + name: 'pref', + description: 'Whether to prefix hex with "0x" (defaults to false)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The string representation in the specified radix', + type: 'string' + } + }, + floatToHex: { + meta: 'function', + description: 'Converts a float to its IEEE 754 hexadecimal representation.', + args: [ + { + name: 'f', + description: 'The float to convert', + type: 'number' + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The hexadecimal string (e.g., "0x41200000" for 10.0)', + type: 'string' + } + }, + doubleToHex: { + meta: 'function', + description: 'Converts a double to its IEEE 754 hexadecimal representation.', + args: [ + { + name: 'd', + description: 'The double to convert', + type: 'number' + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The hexadecimal string (e.g., "0x4024000000000000" for 10.0)', + type: 'string' + } + }, + printUnsignedBytes: { + meta: 'function', + description: 'Converts a list of signed bytes to a list of unsigned integer values.', + args: [ + { + name: 'byteArray', + description: 'The list of bytes to convert', + type: 'array' + } + ], + return: { + description: 'The list of unsigned integers (0-255)', + type: 'array' + } + }, + base64ToHex: { + meta: 'function', + description: 'Converts a Base64 string to a hexadecimal string.', + args: [ + { + name: 'base64', + description: 'The Base64 string to convert', + type: 'string' + } + ], + return: { + description: 'The hexadecimal string', + type: 'string' + } + }, + hexToBase64: { + meta: 'function', + description: 'Converts a hexadecimal string to a Base64 string.', + args: [ + { + name: 'hex', + description: 'The hexadecimal string to convert', + type: 'string' + } + ], + return: { + description: 'The Base64 string', + type: 'string' + } + }, + base64ToBytes: { + meta: 'function', + description: 'Converts a Base64 string to an array of bytes.', + args: [ + { + name: 'input', + description: 'The Base64 string to convert', + type: 'string' + } + ], + return: { + description: 'The array of bytes', + type: 'array' + } + }, + base64ToBytesList: { + meta: 'function', + description: 'Converts a Base64 string to a list of bytes.', + args: [ + { + name: 'input', + description: 'The Base64 string to convert', + type: 'string' + } + ], + return: { + description: 'The list of bytes', + type: 'array' + } + }, + bytesToBase64: { + meta: 'function', + description: 'Converts an array of bytes to a Base64 string.', + args: [ + { + name: 'bytes', + description: 'The array of bytes to convert', + type: 'array' + } + ], + return: { + description: 'The Base64 string', + type: 'string' + } + }, + bytesToHex: { + meta: 'function', + description: 'Converts an array or list of bytes to a hexadecimal string.', + args: [ + { + name: 'bytes', + description: 'The bytes to convert', + type: 'array' + } + ], + return: { + description: 'The hexadecimal string', + type: 'string' + } + }, + toFlatMap: { + meta: 'function', + description: 'Converts a nested map to a flat map, with options for key paths and exclusions.', + args: [ + { + name: 'json', + description: 'The nested map to flatten', + type: 'object' + }, + { + name: 'excludeList', + description: 'List of keys to exclude from flattening', + type: 'array', + optional: true + }, + { + name: 'pathInKey', + description: 'Whether to include full path in keys (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The flattened map', + type: 'object' + } + }, + encodeURI: { + meta: 'function', + description: 'Encodes a URI string, preserving certain characters as per MDN standards.', + args: [ + { + name: 'uri', + description: 'The URI string to encode', + type: 'string' + } + ], + return: { + description: 'The encoded URI string', + type: 'string' + } + }, + decodeURI: { + meta: 'function', + description: 'Decodes a URI string previously encoded with encodeURI.', + args: [ + { + name: 'uri', + description: 'The URI string to decode', + type: 'string' + } + ], + return: { + description: 'The decoded URI string', + type: 'string' + } + }, + raiseError: { + meta: 'function', + description: 'Throws an error with a custom message.', + args: [ + { + name: 'message', + description: 'The error message to throw', + type: 'string' + } + ], + return: { + description: 'Does not return; throws an exception', + type: 'void' + } + }, + isBinary: { + meta: 'function', + description: 'Checks if a string is a binary number.', + args: [ + { + name: 'str', + description: 'The string to check', + type: 'string' + } + ], + return: { + description: '2 if the string is binary, -1 otherwise', + type: 'number' + } + }, + isOctal: { + meta: 'function', + description: 'Checks if a string is an octal number.', + args: [ + { + name: 'str', + description: 'The string to check', + type: 'string' + } + ], + return: { + description: '8 if the string is octal, -1 otherwise', + type: 'number' + } + }, + isDecimal: { + meta: 'function', + description: 'Checks if a string is a decimal number.', + args: [ + { + name: 'str', + description: 'The string to check', + type: 'string' + } + ], + return: { + description: '10 if the string is decimal, -1 otherwise', + type: 'number' + } + }, + isHexadecimal: { + meta: 'function', + description: 'Checks if a string is a hexadecimal number.', + args: [ + { + name: 'str', + description: 'The string to check', + type: 'string' + } + ], + return: { + description: '16 if the string is hexadecimal, -1 otherwise', + type: 'number' + } + }, + bytesToExecutionArrayList: { + meta: 'function', + description: 'Converts an array of bytes to an execution array list.', + args: [ + { + name: 'byteArray', + description: 'The array of bytes to convert', + type: 'array' + } + ], + return: { + description: 'The execution array list of bytes', + type: 'array' + } + }, + padStart: { + meta: 'function', + description: 'Pads the start of a string with a character until it reaches the target length.', + args: [ + { + name: 'str', + description: 'The string to pad', + type: 'string' + }, + { + name: 'targetLength', + description: 'The desired length of the resulting string', + type: 'number' + }, + { + name: 'padString', + description: 'The character to pad with (single character)', + type: 'string' + } + ], + return: { + description: 'The padded string', + type: 'string' + } + }, + padEnd: { + meta: 'function', + description: 'Pads the end of a string with a character until it reaches the target length.', + args: [ + { + name: 'str', + description: 'The string to pad', + type: 'string' + }, + { + name: 'targetLength', + description: 'The desired length of the resulting string', + type: 'number' + }, + { + name: 'padString', + description: 'The character to pad with (single character)', + type: 'string' + } + ], + return: { + description: 'The padded string', + type: 'string' + } + }, + parseByteToBinaryArray: { + meta: 'function', + description: 'Converts a byte to a binary array.', + args: [ + { + name: 'byteValue', + description: 'The byte value to convert', + type: 'number' + }, + { + name: 'binLength', + description: 'The length of the binary array (defaults to 8)', + type: 'number', + optional: true + }, + { + name: 'bigEndian', + description: 'Whether to use big-endian order (defaults to true)', + type: 'boolean', + optional: true + } + ], + return: { + description: 'The binary array (array of 0s and 1s)', + type: 'array' + } + }, + parseBytesToBinaryArray: { + meta: 'function', + description: 'Converts a list or array of bytes to a binary array.', + args: [ + { + name: 'value', + description: 'The bytes to convert', + type: 'array' + }, + { + name: 'binLength', + description: 'The total length of the binary array (defaults to bytes.length * 8)', + type: 'number', + optional: true + } + ], + return: { + description: 'The binary array (array of 0s and 1s)', + type: 'array' + } + }, + parseLongToBinaryArray: { + meta: 'function', + description: 'Converts a long integer to a binary array.', + args: [ + { + name: 'longValue', + description: 'The long integer to convert', + type: 'number' + }, + { + name: 'binLength', + description: 'The length of the binary array (defaults to 64)', + type: 'number', + optional: true + } + ], + return: { + description: 'The binary array (array of 0s and 1s)', + type: 'array' + } + }, + parseBinaryArrayToInt: { + meta: 'function', + description: 'Converts a binary array to an integer.', + args: [ + { + name: 'value', + description: 'The binary array to convert (array of 0s and 1s)', + type: 'array' + }, + { + name: 'offset', + description: 'The starting index in the array (defaults to 0)', + type: 'number', + optional: true + }, + { + name: 'length', + description: 'The number of bits to parse (defaults to array length)', + type: 'number', + optional: true + } + ], + return: { + description: 'The parsed integer', + type: 'number' + } + } +}); + +const tbelUtilsFuncNames = [ + "btoa", + "atob", + "bytesToString", + "decodeToString", + "decodeToJson", + "stringToBytes", + "parseInt", + "parseLong", + "parseFloat", + "parseHexIntLongToFloat", + "parseDouble", + "parseLittleEndianHexToInt", + "parseBigEndianHexToInt", + "parseHexToInt", + "parseBytesToInt", + "parseLittleEndianHexToLong", + "parseBigEndianHexToLong", + "parseHexToLong", + "parseBytesToLong", + "parseLittleEndianHexToFloat", + "parseBigEndianHexToFloat", + "parseHexToFloat", + "parseBytesToFloat", + "parseBytesIntToFloat", + "parseLittleEndianHexToDouble", + "parseBigEndianHexToDouble", + "parseHexToDouble", + "parseBytesToDouble", + "parseBytesLongToDouble", + "toFixed", + "toInt", + "hexToBytes", + "hexToBytesArray", + "intToHex", + "longToHex", + "intLongToRadixString", + "floatToHex", + "doubleToHex", + "printUnsignedBytes", + "base64ToHex", + "hexToBase64", + "base64ToBytes", + "base64ToBytesList", + "bytesToBase64", + "bytesToHex", + "toFlatMap", + "encodeURI", + "decodeURI", + "raiseError", + "isBinary", + "isOctal", + "isDecimal", + "isHexadecimal", + "bytesToExecutionArrayList", + "padStart", + "padEnd", + "parseByteToBinaryArray", + "parseBytesToBinaryArray", + "parseLongToBinaryArray", + "parseBinaryArrayToInt" +]; + +export const tbelUtilsFuncHighlightRules: Array = + tbelUtilsFuncNames.map(funcName => ({ + token: 'tb.tbel-utils-func', + regex: `\\b${funcName}\\b`, + next: 'no_regex' + })); From c55f9592f60543218b1f9c9eb07bde2832a5d57a Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 7 Mar 2025 15:33:19 +0200 Subject: [PATCH 033/116] Fixed for rulechains --- .../app/shared/components/js-func.component.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 682cc872e6..9859fa543e 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -241,6 +241,7 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal this.updateJsWorkerGlobals(); this.initialCompleters = this.jsEditor.completers || []; this.updateCompleters(); + this.updateHighlightRules(); this.editorResize$ = new ResizeObserver(() => { this.onAceEditorResize(); }); @@ -577,22 +578,24 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal private updateHighlightRules(): void { // @ts-ignore - if (!!this.highlightRules && !!this.jsEditor.session.$mode) { + if (!!this.jsEditor.session.$mode) { // @ts-ignore const newMode = new this.jsEditor.session.$mode.constructor(); newMode.$highlightRules = new newMode.HighlightRules(); - for(const group in this.highlightRules) { - if(!!newMode.$highlightRules.$rules[group]) { - newMode.$highlightRules.$rules[group].unshift(...this.highlightRules[group]); - } else { - newMode.$highlightRules.$rules[group] = this.highlightRules[group]; + if (!!this.highlightRules) { + for(const group in this.highlightRules) { + if(!!newMode.$highlightRules.$rules[group]) { + newMode.$highlightRules.$rules[group].unshift(...this.highlightRules[group]); + } else { + newMode.$highlightRules.$rules[group] = this.highlightRules[group]; + } } } if (this.scriptLanguage === ScriptLanguage.TBEL) { newMode.$highlightRules.$rules.start = [...tbelUtilsFuncHighlightRules, ...newMode.$highlightRules.$rules.start]; } const identifierRule = newMode.$highlightRules.$rules.no_regex.find(rule => rule.token?.includes('identifier')); - if (identifierRule) { + if (identifierRule && identifierRule.next === 'no_regex') { identifierRule.next = 'start'; } // @ts-ignore From 5b1731b0d8eac6e0fdc45b6e1b3c40f115dd00c5 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 7 Mar 2025 15:41:18 +0200 Subject: [PATCH 034/116] license header --- .../app/shared/models/ace/tbel-utils.models.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts index 24b6d9eaaf..a595428e63 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts +++ b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts @@ -1,3 +1,19 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + import { AceHighlightRule } from '@shared/models/ace/ace.models'; import { TbEditorCompleter } from '@shared/models/ace/completion.models'; From 9215231ba6eb8c6e1108419bc7a07e9ecdb419dc Mon Sep 17 00:00:00 2001 From: mpetrov Date: Fri, 7 Mar 2025 15:54:45 +0200 Subject: [PATCH 035/116] refactoring --- ui-ngx/src/app/shared/components/js-func.component.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/js-func.component.ts b/ui-ngx/src/app/shared/components/js-func.component.ts index 9859fa543e..f9674c550a 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.ts +++ b/ui-ngx/src/app/shared/components/js-func.component.ts @@ -241,7 +241,6 @@ export class JsFuncComponent implements OnInit, OnChanges, OnDestroy, ControlVal this.updateJsWorkerGlobals(); this.initialCompleters = this.jsEditor.completers || []; this.updateCompleters(); - this.updateHighlightRules(); this.editorResize$ = new ResizeObserver(() => { this.onAceEditorResize(); }); From 28fba7645eada65426956023074620f819fdcae4 Mon Sep 17 00:00:00 2001 From: YevhenBondarenko Date: Mon, 10 Mar 2025 12:06:34 +0100 Subject: [PATCH 036/116] added backward compatibility for api usage --- .../DefaultTbApiUsageStateService.java | 39 ++++++++++++++++--- .../apiusage/TbApiUsageStateService.java | 4 +- .../queue/DefaultTbCoreConsumerService.java | 14 +++---- common/proto/src/main/proto/queue.proto | 20 +++++++--- .../InMemoryMonolithQueueFactory.java | 4 +- .../InMemoryTbTransportQueueFactory.java | 2 +- .../provider/KafkaMonolithQueueFactory.java | 12 +++--- .../provider/KafkaTbCoreQueueFactory.java | 12 +++--- .../KafkaTbRuleEngineQueueFactory.java | 6 +-- .../KafkaTbTransportQueueFactory.java | 6 +-- .../KafkaTbVersionControlQueueFactory.java | 6 +-- .../queue/provider/TbCoreQueueFactory.java | 4 +- .../provider/TbCoreQueueProducerProvider.java | 6 +-- .../provider/TbQueueProducerProvider.java | 4 +- .../TbRuleEngineProducerProvider.java | 6 +-- .../TbTransportQueueProducerProvider.java | 6 +-- .../TbUsageStatsClientQueueFactory.java | 4 +- .../TbVersionControlProducerProvider.java | 6 +-- .../DefaultTbApiUsageReportClient.java | 18 ++++----- 19 files changed, 108 insertions(+), 71 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java index af4da51a45..74926297aa 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/DefaultTbApiUsageStateService.java @@ -61,7 +61,8 @@ import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.dao.tenant.TenantService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.dao.usagerecord.ApiUsageStateService; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.PartitionService; @@ -155,9 +156,30 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService } @Override - public void process(TbProtoQueueMsg msgPack, TbCallback callback) { - String serviceId = msgPack.getValue().getServiceId(); - msgPack.getValue().getMsgsList().forEach(msg -> { + public void process(TbProtoQueueMsg msgPack, TbCallback callback) { + ToUsageStatsServiceMsg serviceMsg = msgPack.getValue(); + String serviceId = serviceMsg.getServiceId(); + + List msgs; + + //For backward compatibility, remove after release + if (serviceMsg.getTenantIdMSB() != 0) { + TransportProtos.UsageStatsServiceMsg oldMsg = TransportProtos.UsageStatsServiceMsg.newBuilder() + .setTenantIdMSB(serviceMsg.getTenantIdMSB()) + .setTenantIdLSB(serviceMsg.getTenantIdLSB()) + .setCustomerIdMSB(serviceMsg.getCustomerIdMSB()) + .setCustomerIdLSB(serviceMsg.getCustomerIdLSB()) + .setEntityIdMSB(serviceMsg.getEntityIdMSB()) + .setEntityIdLSB(serviceMsg.getEntityIdLSB()) + .addAllValues(serviceMsg.getValuesList()) + .build(); + + msgs = List.of(oldMsg); + } else { + msgs = serviceMsg.getMsgsList(); + } + + msgs.forEach(msg -> { TenantId tenantId = TenantId.fromUUID(new UUID(msg.getTenantIdMSB(), msg.getTenantIdLSB())); EntityId ownerId; if (msg.getCustomerIdMSB() != 0 && msg.getCustomerIdLSB() != 0) { @@ -193,7 +215,14 @@ public class DefaultTbApiUsageStateService extends AbstractPartitionBasedService updatedEntries = new ArrayList<>(ApiUsageRecordKey.values().length); Set apiFeatures = new HashSet<>(); for (UsageStatsKVProto statsItem : values) { - ApiUsageRecordKey recordKey = ProtoUtils.fromProto(statsItem.getKey()); + ApiUsageRecordKey recordKey; + + //For backward compatibility, remove after release + if (StringUtils.isNotEmpty(statsItem.getKey())) { + recordKey = ApiUsageRecordKey.valueOf(statsItem.getKey()); + } else { + recordKey = ProtoUtils.fromProto(statsItem.getKeyProto()); + } StatsCalculationResult calculationResult = usageState.calculate(recordKey, statsItem.getValue(), serviceId); if (calculationResult.isValueChanged()) { diff --git a/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java b/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java index 27673ccc92..5b5b1b5225 100644 --- a/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java +++ b/application/src/main/java/org/thingsboard/server/service/apiusage/TbApiUsageStateService.java @@ -22,13 +22,13 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.id.TenantProfileId; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.common.stats.TbApiUsageStateClient; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.discovery.event.PartitionChangeEvent; public interface TbApiUsageStateService extends TbApiUsageStateClient, RuleEngineApiUsageStateService, ApplicationListener { - void process(TbProtoQueueMsg msg, TbCallback callback); + void process(TbProtoQueueMsg msg, TbCallback callback); void onTenantProfileUpdate(TenantProfileId tenantProfileId); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java index 6d4a108107..3aaa36b068 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCoreConsumerService.java @@ -74,7 +74,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.TbTimeSeriesUpdatePr import org.thingsboard.server.gen.transport.TransportProtos.ToCoreMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateServiceMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportToDeviceActorMsg; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -150,7 +150,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService, CoreQueueConfig> mainConsumer; - private QueueConsumerManager> usageStatsConsumer; + private QueueConsumerManager> usageStatsConsumer; private QueueConsumerManager> firmwareStatesConsumer; private volatile ListeningExecutorService deviceActivityEventsExecutor; @@ -207,7 +207,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService>builder() + this.usageStatsConsumer = QueueConsumerManager.>builder() .name("TB Usage Stats") .msgPackProcessor(this::processUsageStatsMsg) .pollInterval(pollInterval) @@ -402,11 +402,11 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService> msgs, TbQueueConsumer> consumer) throws Exception { - ConcurrentMap> pendingMap = msgs.stream().collect( + private void processUsageStatsMsg(List> msgs, TbQueueConsumer> consumer) throws Exception { + ConcurrentMap> pendingMap = msgs.stream().collect( Collectors.toConcurrentMap(s -> UUID.randomUUID(), Function.identity())); CountDownLatch processingTimeoutLatch = new CountDownLatch(1); - TbPackProcessingContext> ctx = new TbPackProcessingContext<>( + TbPackProcessingContext> ctx = new TbPackProcessingContext<>( processingTimeoutLatch, pendingMap, new ConcurrentHashMap<>()); pendingMap.forEach((id, msg) -> { log.trace("[{}] Creating usage stats callback for message: {}", id, msg.getValue()); @@ -453,7 +453,7 @@ public class DefaultTbCoreConsumerService extends AbstractConsumerService msg, TbCallback callback) { + private void handleUsageStats(TbProtoQueueMsg msg, TbCallback callback) { statsService.process(msg, callback); } diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 0e318c3b30..51796d388e 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -1603,11 +1603,24 @@ message ToTransportMsg { } message UsageStatsKVProto { - ApiUsageRecordKeyProto key = 1; + string key = 1 [deprecated=true]; int64 value = 2; + ApiUsageRecordKeyProto keyProto = 3; } message ToUsageStatsServiceMsg { + int64 tenantIdMSB = 1 [deprecated=true]; + int64 tenantIdLSB = 2 [deprecated=true]; + int64 entityIdMSB = 3 [deprecated=true]; + int64 entityIdLSB = 4 [deprecated=true]; + repeated UsageStatsKVProto values = 5 [deprecated=true]; + int64 customerIdMSB = 6 [deprecated=true]; + int64 customerIdLSB = 7 [deprecated=true]; + string serviceId = 8; + repeated UsageStatsServiceMsg msgs = 9; +} + +message UsageStatsServiceMsg { int64 tenantIdMSB = 1; int64 tenantIdLSB = 2; int64 entityIdMSB = 3; @@ -1617,11 +1630,6 @@ message ToUsageStatsServiceMsg { int64 customerIdLSB = 7; } -message ToUsageStatsServiceMsgPack { - repeated ToUsageStatsServiceMsg msgs = 1; - string serviceId = 2; -} - message ToOtaPackageStateServiceMsg { int64 ts = 1; int64 tenantIdMSB = 2; diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java index d4ca701b51..d70cad159b 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryMonolithQueueFactory.java @@ -140,7 +140,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { return new InMemoryTbQueueConsumer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } @@ -155,7 +155,7 @@ public class InMemoryMonolithQueueFactory implements TbCoreQueueFactory, TbRuleE } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new InMemoryTbQueueProducer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java index 2d8e124172..4ee79aef60 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/InMemoryTbTransportQueueFactory.java @@ -116,7 +116,7 @@ public class InMemoryTbTransportQueueFactory implements TbTransportQueueFactory } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { return new InMemoryTbQueueProducer<>(storage, topicService.buildTopicName(coreSettings.getUsageStatsTopic())); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java index 18d1a3af00..dd5d61e834 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaMonolithQueueFactory.java @@ -35,7 +35,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -320,13 +320,13 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); consumerBuilder.clientId("monolith-us-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId(topicService.buildTopicName("monolith-us-consumer")); - consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(coreAdmin); consumerBuilder.statsService(consumerStatsService); return consumerBuilder.build(); @@ -356,8 +356,8 @@ public class KafkaMonolithQueueFactory implements TbCoreQueueFactory, TbRuleEngi } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("monolith-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java index b6a2e252ff..cc0e044917 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbCoreQueueFactory.java @@ -34,7 +34,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -269,13 +269,13 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { - TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); + public TbQueueConsumer> createToUsageStatsServiceMsgConsumer() { + TbKafkaConsumerTemplate.TbKafkaConsumerTemplateBuilder> consumerBuilder = TbKafkaConsumerTemplate.builder(); consumerBuilder.settings(kafkaSettings); consumerBuilder.topic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); consumerBuilder.clientId("tb-core-us-consumer-" + serviceInfoProvider.getServiceId()); consumerBuilder.groupId(topicService.buildTopicName("tb-core-us-consumer")); - consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsgPack.parseFrom(msg.getData()), msg.getHeaders())); + consumerBuilder.decoder(msg -> new TbProtoQueueMsg<>(msg.getKey(), ToUsageStatsServiceMsg.parseFrom(msg.getData()), msg.getHeaders())); consumerBuilder.admin(coreAdmin); consumerBuilder.statsService(consumerStatsService); return consumerBuilder.build(); @@ -305,8 +305,8 @@ public class KafkaTbCoreQueueFactory implements TbCoreQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-core-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java index 68f5fee9c2..87a1a69c2e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbRuleEngineQueueFactory.java @@ -33,7 +33,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; import org.thingsboard.server.queue.TbQueueProducer; @@ -274,8 +274,8 @@ public class KafkaTbRuleEngineQueueFactory implements TbRuleEngineQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-rule-engine-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java index daa78a08f6..dd260840f5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbTransportQueueFactory.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMs import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; import org.thingsboard.server.queue.TbQueueAdmin; @@ -165,8 +165,8 @@ public class KafkaTbTransportQueueFactory implements TbTransportQueueFactory { } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("transport-node-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java index 7e6c05dcae..aacebb8579 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/KafkaTbVersionControlQueueFactory.java @@ -20,7 +20,7 @@ import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.stereotype.Component; import org.thingsboard.server.gen.transport.TransportProtos.ToCoreNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperServiceMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueAdmin; import org.thingsboard.server.queue.TbQueueConsumer; @@ -98,8 +98,8 @@ public class KafkaTbVersionControlQueueFactory implements TbVersionControlQueueF } @Override - public TbQueueProducer> createToUsageStatsServiceMsgProducer() { - TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); + public TbQueueProducer> createToUsageStatsServiceMsgProducer() { + TbKafkaProducerTemplate.TbKafkaProducerTemplateBuilder> requestBuilder = TbKafkaProducerTemplate.builder(); requestBuilder.settings(kafkaSettings); requestBuilder.clientId("tb-vc-us-producer-" + serviceInfoProvider.getServiceId()); requestBuilder.defaultTopic(topicService.buildTopicName(coreSettings.getUsageStatsTopic())); diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java index b9ccfd1866..c4002f4d3e 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueFactory.java @@ -28,7 +28,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToOtaPackageStateSer import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiRequestMsg; import org.thingsboard.server.gen.transport.TransportProtos.TransportApiResponseMsg; @@ -91,7 +91,7 @@ public interface TbCoreQueueFactory extends TbUsageStatsClientQueueFactory, Hous * * @return */ - TbQueueConsumer> createToUsageStatsServiceMsgConsumer(); + TbQueueConsumer> createToUsageStatsServiceMsgConsumer(); /** * Used to consume messages about firmware update notifications by TB Core Service diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java index 386a525b28..9cf18e6cb4 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbCoreQueueProducerProvider.java @@ -26,7 +26,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -45,7 +45,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { private TbQueueProducer> toEdge; private TbQueueProducer> toEdgeNotifications; private TbQueueProducer> toEdgeEvents; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toVersionControl; private TbQueueProducer> toHousekeeper; @@ -94,7 +94,7 @@ public class TbCoreQueueProducerProvider implements TbQueueProducerProvider { } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java index d5c011c7b9..ec31763baa 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbQueueProducerProvider.java @@ -24,7 +24,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -74,7 +74,7 @@ public interface TbQueueProducerProvider { * * @return */ - TbQueueProducer> getTbUsageStatsMsgProducer(); + TbQueueProducer> getTbUsageStatsMsgProducer(); /** * Used to push messages to other instances of TB Core Service diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java index 835b02ec8e..e9f7773a26 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbRuleEngineProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -42,7 +42,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider { private TbQueueProducer> toTbCore; private TbQueueProducer> toRuleEngineNotifications; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; private TbQueueProducer> toEdge; private TbQueueProducer> toEdgeNotifications; @@ -107,7 +107,7 @@ public class TbRuleEngineProducerProvider implements TbQueueProducerProvider { } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java index 689d236de7..7960cbcf32 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbTransportQueueProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -40,7 +40,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider private TbQueueProducer> toRuleEngine; private TbQueueProducer> toTbCore; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; public TbTransportQueueProducerProvider(TbTransportQueueFactory tbQueueProvider) { @@ -102,7 +102,7 @@ public class TbTransportQueueProducerProvider implements TbQueueProducerProvider } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java index c4c5f5215a..0c551fc998 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbUsageStatsClientQueueFactory.java @@ -15,12 +15,12 @@ */ package org.thingsboard.server.queue.provider; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; public interface TbUsageStatsClientQueueFactory { - TbQueueProducer> createToUsageStatsServiceMsgProducer(); + TbQueueProducer> createToUsageStatsServiceMsgProducer(); } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java index 400ccfc085..cd4fa12df0 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/provider/TbVersionControlProducerProvider.java @@ -27,7 +27,7 @@ import org.thingsboard.server.gen.transport.TransportProtos.ToHousekeeperService import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToRuleEngineNotificationMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToTransportMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; +import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToVersionControlServiceMsg; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -38,7 +38,7 @@ public class TbVersionControlProducerProvider implements TbQueueProducerProvider private final TbVersionControlQueueFactory tbQueueProvider; private TbQueueProducer> toTbCoreNotifications; - private TbQueueProducer> toUsageStats; + private TbQueueProducer> toUsageStats; private TbQueueProducer> toHousekeeper; public TbVersionControlProducerProvider(TbVersionControlQueueFactory tbQueueProvider) { @@ -98,7 +98,7 @@ public class TbVersionControlProducerProvider implements TbQueueProducerProvider } @Override - public TbQueueProducer> getTbUsageStatsMsgProducer() { + public TbQueueProducer> getTbUsageStatsMsgProducer() { return toUsageStats; } diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java index 8c0439362b..d26042d114 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/usagestats/DefaultTbApiUsageReportClient.java @@ -32,8 +32,8 @@ import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; import org.thingsboard.server.common.stats.TbApiUsageReportClient; import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.gen.transport.TransportProtos; +import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsServiceMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsg; -import org.thingsboard.server.gen.transport.TransportProtos.ToUsageStatsServiceMsgPack; import org.thingsboard.server.gen.transport.TransportProtos.UsageStatsKVProto; import org.thingsboard.server.queue.TbQueueProducer; import org.thingsboard.server.queue.common.TbProtoQueueMsg; @@ -74,7 +74,7 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { private final TbServiceInfoProvider serviceInfoProvider; private final SchedulerComponent scheduler; private final TbQueueProducerProvider producerProvider; - private TbQueueProducer> msgProducer; + private TbQueueProducer> msgProducer; @PostConstruct private void init() { @@ -94,7 +94,7 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { } private void reportStats() { - ConcurrentMap report = new ConcurrentHashMap<>(); + ConcurrentMap report = new ConcurrentHashMap<>(); for (ApiUsageRecordKey key : ApiUsageRecordKey.values()) { ConcurrentMap statsForKey = stats.get(key); @@ -102,8 +102,8 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { long value = statsValue.get(); if (value == 0 && key.isCounter()) return; - ToUsageStatsServiceMsg.Builder statsMsg = report.computeIfAbsent(reportLevel.getParentEntity(), parent -> { - ToUsageStatsServiceMsg.Builder newStatsMsg = ToUsageStatsServiceMsg.newBuilder(); + UsageStatsServiceMsg.Builder statsMsg = report.computeIfAbsent(reportLevel.getParentEntity(), parent -> { + UsageStatsServiceMsg.Builder newStatsMsg = UsageStatsServiceMsg.newBuilder(); TenantId tenantId = parent.getTenantId(); newStatsMsg.setTenantIdMSB(tenantId.getId().getMostSignificantBits()); @@ -119,13 +119,13 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { }); UsageStatsKVProto.Builder statsItem = UsageStatsKVProto.newBuilder() - .setKey(ProtoUtils.toProto(key)) + .setKeyProto(ProtoUtils.toProto(key)) .setValue(value); statsMsg.addValues(statsItem.build()); }); } - Map> reportStatsPerTpi = new HashMap<>(); + Map> reportStatsPerTpi = new HashMap<>(); report.forEach((parent, statsMsg) -> { try { @@ -152,11 +152,11 @@ public class DefaultTbApiUsageReportClient implements TbApiUsageReportClient { } } - private List toMsgPack(List list) { + private List toMsgPack(List list) { return Lists.partition(list, packSize) .stream() .map(partition -> - ToUsageStatsServiceMsgPack.newBuilder() + ToUsageStatsServiceMsg.newBuilder() .addAllMsgs(partition) .setServiceId(serviceInfoProvider.getServiceId()) .build()) From 08b05e200f1eb2d52893b8bec2c6ecdd72b2d15f Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 11 Mar 2025 09:37:29 +0200 Subject: [PATCH 037/116] UI: Metric lable to Absolute --- .../main/data/json/system/scada_symbols/cylindrical-tank.svg | 2 +- .../src/main/data/json/system/scada_symbols/elevated-tank.svg | 2 +- .../main/data/json/system/scada_symbols/horizontal-tank-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/horizontal-tank.svg | 2 +- .../data/json/system/scada_symbols/large-cylindrical-tank.svg | 2 +- .../json/system/scada_symbols/large-stand-cylindrical-tank.svg | 2 +- .../json/system/scada_symbols/large-stand-vertical-tank.svg | 2 +- .../main/data/json/system/scada_symbols/large-vertical-tank.svg | 2 +- application/src/main/data/json/system/scada_symbols/pool-hp.svg | 2 +- .../data/json/system/scada_symbols/short-vertical-tank-hp.svg | 2 +- .../data/json/system/scada_symbols/small-cylindrical-tank.svg | 2 +- .../data/json/system/scada_symbols/small-spherical-tank.svg | 2 +- .../src/main/data/json/system/scada_symbols/spherical-tank.svg | 2 +- .../data/json/system/scada_symbols/stand-cylindrical-tank.svg | 2 +- .../data/json/system/scada_symbols/stand-horizontal-tank.svg | 2 +- .../json/system/scada_symbols/stand-vertical-short-tank.svg | 2 +- .../main/data/json/system/scada_symbols/stand-vertical-tank.svg | 2 +- .../main/data/json/system/scada_symbols/vertical-short-tank.svg | 2 +- .../main/data/json/system/scada_symbols/vertical-tank-hp.svg | 2 +- .../src/main/data/json/system/scada_symbols/vertical-tank.svg | 2 +- 20 files changed, 20 insertions(+), 20 deletions(-) diff --git a/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg index ab0b5415bd..acb895cd5a 100644 --- a/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/cylindrical-tank.svg @@ -362,7 +362,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/elevated-tank.svg b/application/src/main/data/json/system/scada_symbols/elevated-tank.svg index 7019e3221a..48668e9851 100644 --- a/application/src/main/data/json/system/scada_symbols/elevated-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/elevated-tank.svg @@ -367,7 +367,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg index 2adde5881f..18f194684b 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-tank-hp.svg @@ -340,7 +340,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg b/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg index f410d709f4..b6b6eede7b 100644 --- a/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/horizontal-tank.svg @@ -362,7 +362,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg index 98f61f0094..69360fbe9c 100644 --- a/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-cylindrical-tank.svg @@ -362,7 +362,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg index ac94438463..11bd47916f 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-cylindrical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ] }, diff --git a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg index 5b534b615c..d9c05bde40 100644 --- a/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-stand-vertical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg index 33bd6c2f39..cc168915ad 100644 --- a/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/large-vertical-tank.svg @@ -362,7 +362,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/pool-hp.svg b/application/src/main/data/json/system/scada_symbols/pool-hp.svg index 74757b77d6..925ea8906a 100644 --- a/application/src/main/data/json/system/scada_symbols/pool-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/pool-hp.svg @@ -340,7 +340,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg index 1ce12cafe2..046c5c5802 100644 --- a/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/short-vertical-tank-hp.svg @@ -340,7 +340,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg index 9af2be50c4..d4ddda1895 100644 --- a/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/small-cylindrical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg b/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg index e0b50e3200..b8e3987188 100644 --- a/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/small-spherical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg index 11698d6636..cba49c63e0 100644 --- a/application/src/main/data/json/system/scada_symbols/spherical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/spherical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg index 9ee0eb5122..a78060dfaf 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-cylindrical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg index 5ec5f34b8f..63a21bcf08 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-horizontal-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg index a92ba1e274..96df175589 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-vertical-short-tank.svg @@ -364,7 +364,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg index 1b19157341..0d0e368b9b 100644 --- a/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/stand-vertical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ] }, diff --git a/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg b/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg index 23fe4a2733..57a79d72d7 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-short-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg index e1b57d7906..491fb4477e 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-tank-hp.svg @@ -340,7 +340,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, diff --git a/application/src/main/data/json/system/scada_symbols/vertical-tank.svg b/application/src/main/data/json/system/scada_symbols/vertical-tank.svg index 868256e3df..99fa9b649c 100644 --- a/application/src/main/data/json/system/scada_symbols/vertical-tank.svg +++ b/application/src/main/data/json/system/scada_symbols/vertical-tank.svg @@ -363,7 +363,7 @@ }, { "value": false, - "label": "Metric" + "label": "Absolute" } ], "disabled": false, From e1923d0ce0f208ca9cdfa205ff611ba58d3c1181 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Tue, 11 Mar 2025 10:43:34 +0200 Subject: [PATCH 038/116] Improve KafkaEdgeTopicsCleanUpService --- .../service/ttl/KafkaEdgeTopicsCleanUpService.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java index 5a74f9f69a..73712542fd 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/KafkaEdgeTopicsCleanUpService.java @@ -53,8 +53,6 @@ import static org.thingsboard.server.service.state.DefaultDeviceStateService.LAS @ConditionalOnExpression("'${queue.type:null}'=='kafka' && ${edges.enabled:true} && ${sql.ttl.edge_events.edge_events_ttl:0} > 0") public class KafkaEdgeTopicsCleanUpService extends AbstractCleanUpService { - private static final String EDGE_EVENT_TOPIC_NAME = "tb_edge_event.notifications."; - private final TopicService topicService; private final TenantService tenantService; private final EdgeService edgeService; @@ -64,6 +62,9 @@ public class KafkaEdgeTopicsCleanUpService extends AbstractCleanUpService { @Value("${sql.ttl.edge_events.edge_events_ttl:2628000}") private long ttlSeconds; + @Value("${queue.edge.event-notifications-topic:tb_edge_event.notifications}") + private String tbEdgeEventNotificationsTopic; + public KafkaEdgeTopicsCleanUpService(PartitionService partitionService, EdgeService edgeService, TenantService tenantService, AttributesService attributesService, TopicService topicService, TbKafkaSettings kafkaSettings, TbKafkaTopicConfigs kafkaTopicConfigs) { @@ -86,7 +87,7 @@ public class KafkaEdgeTopicsCleanUpService extends AbstractCleanUpService { return; } - String edgeTopicPrefix = topicService.buildTopicName(EDGE_EVENT_TOPIC_NAME); + String edgeTopicPrefix = topicService.buildTopicName(tbEdgeEventNotificationsTopic); List matchingTopics = topics.stream().filter(topic -> topic.startsWith(edgeTopicPrefix)).toList(); if (matchingTopics.isEmpty()) { log.debug("No matching topics found with prefix [{}]. Skipping cleanup.", edgeTopicPrefix); @@ -147,7 +148,7 @@ public class KafkaEdgeTopicsCleanUpService extends AbstractCleanUpService { try { String remaining = topic.substring(prefix.length()); String[] parts = remaining.split("\\."); - TenantId tenantId = new TenantId(UUID.fromString(parts[0])); + TenantId tenantId = TenantId.fromUUID(UUID.fromString(parts[0])); EdgeId edgeId = new EdgeId(UUID.fromString(parts[1])); tenantEdgeMap.computeIfAbsent(tenantId, id -> new ArrayList<>()).add(edgeId); } catch (Exception e) { From 6ca15fe600196aeb1d59418554e2b47ab3801311 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Tue, 11 Mar 2025 10:51:24 +0200 Subject: [PATCH 039/116] UI: Fixed drag and drop for data keys chip --- .../home/components/widget/config/data-keys.component.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss index 8b377a8456..0329b24432 100644 --- a/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss +++ b/ui-ngx/src/app/modules/home/components/widget/config/data-keys.component.scss @@ -19,7 +19,7 @@ width: 100%; input.tb-dragging { - display: none; + visibility: hidden; } } From e7b931690aa48db8ac45602599a364f8e48df14b Mon Sep 17 00:00:00 2001 From: Artem Barysh Date: Tue, 11 Mar 2025 15:21:33 +0200 Subject: [PATCH 040/116] TBEL formatting --- .../shared/models/ace/tbel-utils.models.ts | 198 +++++++++--------- 1 file changed, 99 insertions(+), 99 deletions(-) diff --git a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts index a595428e63..53d0ccdd15 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts +++ b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts @@ -23,7 +23,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Encodes a string to Base64.', args: [ { - name: 'input', + name: 'str', description: 'The string to encode', type: 'string' } @@ -38,7 +38,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Decodes a Base64 encoded string.', args: [ { - name: 'encoded', + name: 'str', description: 'The Base64 encoded string to decode', type: 'string' } @@ -53,9 +53,9 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a list of bytes to a string, optionally specifying the charset.', args: [ { - name: 'bytesList', + name: 'data', description: 'The list of bytes to convert', - type: 'array' + type: 'list' }, { name: 'charsetName', @@ -71,12 +71,12 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, decodeToString: { meta: 'function', - description: 'Converts a list of bytes to a string using the default charset.', + description: 'Converts a list of bytes to a string.', args: [ { - name: 'bytesList', + name: 'data', description: 'The list of bytes to convert', - type: 'array' + type: 'list' } ], return: { @@ -89,13 +89,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a JSON string or converts a list of bytes to a string and parses it as JSON.', args: [ { - name: 'input', - description: 'The JSON string or list of bytes to parse', - type: 'string | array' + name: 'data', + description: 'The JSON string or list of bytes to parse into JSON object', + type: 'string | list' } ], return: { - description: 'The parsed JSON object (e.g., object, array, or primitive)', + description: 'The parsed JSON object', type: 'object' } }, @@ -117,7 +117,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ ], return: { description: 'The list of bytes representing the string', - type: 'array' + type: 'list' } }, parseInt: { @@ -125,13 +125,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a string to an integer, optionally specifying the radix.', args: [ { - name: 'value', + name: 'str', description: 'The string to parse', type: 'string' }, { name: 'radix', - description: 'The radix for parsing (e.g., 2 for binary, 16 for hex, defaults to auto-detection if 0)', + description: 'The radix for parsing (e.g., 2 for binary, 16 for hex). If omitted, it is auto-detected (e.g., 0x for hex).', type: 'number', optional: true } @@ -146,13 +146,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a string to a long integer, optionally specifying the radix.', args: [ { - name: 'value', + name: 'str', description: 'The string to parse', type: 'string' }, { name: 'radix', - description: 'The radix for parsing (e.g., 2 for binary, 16 for hex, defaults to auto-detection if 0)', + description: 'The radix for parsing (e.g., 2 for binary, 16 for hex). If omitted, it is auto-detected (e.g., 0x for hex).', type: 'number', optional: true } @@ -164,16 +164,16 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, parseFloat: { meta: 'function', - description: 'Parses a string to a float. If radix is 16, interprets the string as hexadecimal IEEE 754 float bits.', + description: 'Parses a string to a float, optionally specifying the radix.', args: [ { - name: 'value', + name: 'str', description: 'The string to parse', type: 'string' }, { name: 'radix', - description: 'The radix for parsing (e.g., 16 for hex, defaults to 10 if 0)', + description: 'The radix for parsing (e.g., 16 indicates a standard IEEE 754 hexadecimal float, defaults to 10 if unspecified)', type: 'number', optional: true } @@ -188,7 +188,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a hexadecimal string to a float, treating it as an integer value.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to parse (e.g., "0x0A" for 10.0)', type: 'string' }, @@ -205,16 +205,16 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, parseDouble: { meta: 'function', - description: 'Parses a string to a double. If radix is 16, interprets the string as hexadecimal IEEE 754 double bits.', + description: 'Parses a string to a double, optionally specifying the radix.', args: [ { - name: 'value', + name: 'str', description: 'The string to parse', type: 'string' }, { name: 'radix', - description: 'The radix for parsing (e.g., 16 for hex, defaults to 10 if unspecified)', + description: 'The radix for parsing (e.g., 16 indicates a standard IEEE 754 double bits, defaults to 10 if unspecified)', type: 'number', optional: true } @@ -259,7 +259,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a hexadecimal string to an integer, optionally specifying endianness.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to parse', type: 'string' }, @@ -282,11 +282,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -343,7 +343,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a hexadecimal string to a long integer, optionally specifying endianness.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to parse', type: 'string' }, @@ -366,11 +366,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -427,7 +427,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a hexadecimal string to a float using IEEE 754 format, optionally specifying endianness.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to parse', type: 'string' }, @@ -450,11 +450,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -483,11 +483,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -544,7 +544,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Parses a hexadecimal string to a double using IEEE 754 format, optionally specifying endianness.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to parse', type: 'string' }, @@ -567,11 +567,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -600,11 +600,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ { name: 'data', description: 'The bytes to parse', - type: 'array' + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the byte array', + description: 'The starting index in the byte list or array (defaults to 0)', type: 'number', optional: true }, @@ -628,11 +628,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, toFixed: { meta: 'function', - description: 'Rounds a number to a specified number of decimal places.', + description: 'Rounds a floating-point number to a set precision using half-up rounding.', args: [ { name: 'value', - description: 'The number to round', + description: 'The floating-point number', type: 'number' }, { @@ -642,17 +642,17 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ } ], return: { - description: 'The rounded number', + description: 'The rounded floating-point number.', type: 'number' } }, toInt: { meta: 'function', - description: 'Converts a double to an integer by rounding.', + description: 'Converts a floating-point number to an integer by half-up rounding.', args: [ { name: 'value', - description: 'The double to convert', + description: 'The floating-point number to convert', type: 'number' } ], @@ -666,14 +666,14 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a hexadecimal string to a list of bytes.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to convert', type: 'string' } ], return: { description: 'The list of bytes', - type: 'array' + type: 'list' } }, hexToBytesArray: { @@ -681,7 +681,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a hexadecimal string to an array of bytes.', args: [ { - name: 'value', + name: 'hex', description: 'The hexadecimal string to convert', type: 'string' } @@ -696,7 +696,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts an integer to a hexadecimal string.', args: [ { - name: 'i', + name: 'value', description: 'The integer to convert', type: 'number' }, @@ -707,13 +707,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ optional: true }, { - name: 'pref', + name: 'prefix', description: 'Whether to prefix with "0x" (defaults to false)', type: 'boolean', optional: true }, { - name: 'len', + name: 'length', description: 'The desired length of the hex string (defaults to minimum required)', type: 'number', optional: true @@ -729,7 +729,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a long integer to a hexadecimal string.', args: [ { - name: 'l', + name: 'value', description: 'The long integer to convert', type: 'number' }, @@ -740,13 +740,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ optional: true }, { - name: 'pref', + name: 'prefix', description: 'Whether to prefix with "0x" (defaults to false)', type: 'boolean', optional: true }, { - name: 'len', + name: 'length', description: 'The desired length of the hex string (defaults to minimum required)', type: 'number', optional: true @@ -762,13 +762,13 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a long integer to a string in the specified radix.', args: [ { - name: 'number', + name: 'value', description: 'The number to convert', type: 'number' }, { name: 'radix', - description: 'The radix for conversion (e.g., 2, 8, 10, 16, defaults to 10)', + description: 'The radix for conversion (e.g., 2 for binary, 16 for hex). If omitted, it defaults to 10.', type: 'number', optional: true }, @@ -779,7 +779,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ optional: true }, { - name: 'pref', + name: 'prefix', description: 'Whether to prefix hex with "0x" (defaults to false)', type: 'boolean', optional: true @@ -795,7 +795,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a float to its IEEE 754 hexadecimal representation.', args: [ { - name: 'f', + name: 'value', description: 'The float to convert', type: 'number' }, @@ -807,7 +807,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ } ], return: { - description: 'The hexadecimal string (e.g., "0x41200000" for 10.0)', + description: 'The hexadecimal string', type: 'string' } }, @@ -816,7 +816,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a double to its IEEE 754 hexadecimal representation.', args: [ { - name: 'd', + name: 'value', description: 'The double to convert', type: 'number' }, @@ -828,7 +828,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ } ], return: { - description: 'The hexadecimal string (e.g., "0x4024000000000000" for 10.0)', + description: 'The hexadecimal string', type: 'string' } }, @@ -837,14 +837,14 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a list of signed bytes to a list of unsigned integer values.', args: [ { - name: 'byteArray', + name: 'data', description: 'The list of bytes to convert', - type: 'array' + type: 'list' } ], return: { description: 'The list of unsigned integers (0-255)', - type: 'array' + type: 'list' } }, base64ToHex: { @@ -852,7 +852,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a Base64 string to a hexadecimal string.', args: [ { - name: 'base64', + name: 'str', description: 'The Base64 string to convert', type: 'string' } @@ -882,7 +882,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a Base64 string to an array of bytes.', args: [ { - name: 'input', + name: 'str', description: 'The Base64 string to convert', type: 'string' } @@ -897,14 +897,14 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a Base64 string to a list of bytes.', args: [ { - name: 'input', + name: 'str', description: 'The Base64 string to convert', type: 'string' } ], return: { description: 'The list of bytes', - type: 'array' + type: 'list' } }, bytesToBase64: { @@ -912,7 +912,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts an array of bytes to a Base64 string.', args: [ { - name: 'bytes', + name: 'data', description: 'The array of bytes to convert', type: 'array' } @@ -924,12 +924,12 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, bytesToHex: { meta: 'function', - description: 'Converts an array or list of bytes to a hexadecimal string.', + description: 'Converts a list or array of bytes to a hexadecimal string.', args: [ { - name: 'bytes', + name: 'data', description: 'The bytes to convert', - type: 'array' + type: 'list | array' } ], return: { @@ -939,7 +939,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, toFlatMap: { meta: 'function', - description: 'Converts a nested map to a flat map, with options for key paths and exclusions.', + description: 'Converts a nested map to a flat map, with customizable key paths and exclusions', args: [ { name: 'json', @@ -947,9 +947,9 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ type: 'object' }, { - name: 'excludeList', + name: 'excludeKeys', description: 'List of keys to exclude from flattening', - type: 'array', + type: 'list', optional: true }, { @@ -969,7 +969,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Encodes a URI string, preserving certain characters as per MDN standards.', args: [ { - name: 'uri', + name: 'str', description: 'The URI string to encode', type: 'string' } @@ -981,10 +981,10 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, decodeURI: { meta: 'function', - description: 'Decodes a URI string previously encoded with encodeURI.', + description: 'Decodes a URI string previously encoded.', args: [ { - name: 'uri', + name: 'str', description: 'The URI string to decode', type: 'string' } @@ -999,7 +999,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Throws an error with a custom message.', args: [ { - name: 'message', + name: 'str', description: 'The error message to throw', type: 'string' } @@ -1071,17 +1071,17 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ }, bytesToExecutionArrayList: { meta: 'function', - description: 'Converts an array of bytes to an execution array list.', + description: 'Converts an array of bytes to a list.', args: [ { - name: 'byteArray', + name: 'data', description: 'The array of bytes to convert', type: 'array' } ], return: { - description: 'The execution array list of bytes', - type: 'array' + description: 'The list of bytes', + type: 'list' } }, padStart: { @@ -1094,7 +1094,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ type: 'string' }, { - name: 'targetLength', + name: 'length', description: 'The desired length of the resulting string', type: 'number' }, @@ -1119,7 +1119,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ type: 'string' }, { - name: 'targetLength', + name: 'length', description: 'The desired length of the resulting string', type: 'number' }, @@ -1139,12 +1139,12 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a byte to a binary array.', args: [ { - name: 'byteValue', + name: 'value', description: 'The byte value to convert', type: 'number' }, { - name: 'binLength', + name: 'length', description: 'The length of the binary array (defaults to 8)', type: 'number', optional: true @@ -1157,7 +1157,7 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ } ], return: { - description: 'The binary array (array of 0s and 1s)', + description: 'The binary array', type: 'array' } }, @@ -1166,19 +1166,19 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a list or array of bytes to a binary array.', args: [ { - name: 'value', + name: 'data', description: 'The bytes to convert', - type: 'array' + type: 'list | array' }, { - name: 'binLength', + name: 'length', description: 'The total length of the binary array (defaults to bytes.length * 8)', type: 'number', optional: true } ], return: { - description: 'The binary array (array of 0s and 1s)', + description: 'The binary array', type: 'array' } }, @@ -1187,34 +1187,34 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ description: 'Converts a long integer to a binary array.', args: [ { - name: 'longValue', + name: 'value', description: 'The long integer to convert', type: 'number' }, { - name: 'binLength', + name: 'length', description: 'The length of the binary array (defaults to 64)', type: 'number', optional: true } ], return: { - description: 'The binary array (array of 0s and 1s)', + description: 'The binary array', type: 'array' } }, parseBinaryArrayToInt: { meta: 'function', - description: 'Converts a binary array to an integer.', + description: 'Converts a binary list or array to an integer.', args: [ { - name: 'value', - description: 'The binary array to convert (array of 0s and 1s)', - type: 'array' + name: 'data', + description: 'The binary list or array to convert', + type: 'list | array' }, { name: 'offset', - description: 'The starting index in the array (defaults to 0)', + description: 'The starting index in the binary list or array (defaults to 0)', type: 'number', optional: true }, From 8c7c54b554f5cdd9a38980eee84269065430d671 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 11 Mar 2025 18:15:47 +0200 Subject: [PATCH 041/116] Calculated adjustments --- .../calculated-fields-table-config.ts | 11 ++++++++-- ...lated-field-arguments-table.component.html | 2 +- ...culated-field-arguments-table.component.ts | 15 ++++++++++++- ...calculated-field-debug-dialog.component.ts | 4 ++-- ...ulated-field-argument-panel.component.html | 5 +++-- ...lculated-field-argument-panel.component.ts | 18 +++++++++++---- .../vc/entity-version-create.component.ts | 3 ++- .../import-export/import-export.service.ts | 22 +------------------ .../shared/models/calculated-field.models.ts | 8 +++---- .../assets/locale/locale.constant-en_US.json | 15 +++++++------ 10 files changed, 58 insertions(+), 45 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index cd9f0373db..60581249d2 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -258,8 +258,15 @@ export class CalculatedFieldsTableConfig extends EntityTableConfig this.getCalculatedFieldDialog(calculatedField, 'action.add')), + filter(Boolean), + switchMap(calculatedField => this.calculatedFieldsService.saveCalculatedField(calculatedField)), + filter(Boolean), + takeUntilDestroyed(this.destroyRef) + ) .subscribe(() => this.updateData()); } diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html index 162bd3aa1e..abb34cb502 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/arguments-table/calculated-field-arguments-table.component.html @@ -97,7 +97,7 @@ matTooltipPosition="above"> ([]); entityNameMap = new Map(); + entityNameErrorSet = new Set(); sortOrder = { direction: 'asc', property: '' }; dataSource = new CalculatedFieldArgumentDatasource(); @@ -168,6 +171,7 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces buttonTitle: this.argumentsFormArray.at(index)?.value ? 'action.apply' : 'action.add', tenantId: this.tenantId, entityName: this.entityName, + entityHasError: this.entityNameErrorSet.has(argument.refEntityId?.id), usedArgumentNames: this.argumentsFormArray.value.map(({ argumentName }) => argumentName).filter(name => name !== argument.argumentName), }; this.popoverComponent = this.popoverService.displayPopover(trigger, this.renderer, @@ -198,6 +202,8 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces if (this.calculatedFieldType === CalculatedFieldType.SIMPLE && this.argumentsFormArray.controls.some(control => control.value.refEntityKey.type === ArgumentType.Rolling)) { this.errorText = 'calculated-fields.hint.arguments-simple-with-rolling'; + } else if (this.entityNameErrorSet.size) { + this.errorText = 'calculated-fields.hint.arguments-entity-not-found'; } else if (!this.argumentsFormArray.controls.length) { this.errorText = 'calculated-fields.hint.arguments-empty'; } else { @@ -234,11 +240,18 @@ export class CalculatedFieldArgumentsTableComponent implements ControlValueAcces } private updateEntityNameMap(value: CalculatedFieldArgumentValue[]): void { + this.entityNameErrorSet.clear(); value.forEach(({ refEntityId = {}}) => { if (refEntityId.id && !this.entityNameMap.has(refEntityId.id)) { const { id, entityType } = refEntityId as EntityId; this.entityService.getEntity(entityType as EntityType, id, { ignoreLoading: true, ignoreErrors: true }) - .pipe(takeUntilDestroyed(this.destroyRef)) + .pipe( + catchError(() => { + this.entityNameErrorSet.add(id); + return NEVER; + }), + takeUntilDestroyed(this.destroyRef) + ) .subscribe(entity => this.entityNameMap.set(id, entity.name)); } }); diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts index 8618a11990..880de7c281 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts @@ -20,7 +20,7 @@ import { Store } from '@ngrx/store'; import { AppState } from '@core/core.state'; import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; -import { CalculatedFieldEventBody, DebugEventType, EventType } from '@shared/models/event.models'; +import { CalculatedFieldEventBody, DebugEventType, Event, EventType } from '@shared/models/event.models'; import { EventTableComponent } from '@home/components/event/event-table.component'; import { CalculatedFieldDebugDialogData, CalculatedFieldType } from '@shared/models/calculated-field.models'; @@ -46,7 +46,7 @@ export class CalculatedFieldDebugDialogComponent extends DialogComponent this.data.value.type === CalculatedFieldType.SCRIPT; + this.eventsTable.entitiesTable.cellActionDescriptors[0].isEnabled = (event => this.data.value.type === CalculatedFieldType.SCRIPT && !!(event as Event).body.arguments) } cancel(): void { diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html index 79f2b6ebbc..15286af377 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.html @@ -82,6 +82,7 @@
{{ ArgumentEntityTypeParamsMap.get(entityType).title | translate }}
} @else {
-
{{ 'calculated-fields.time-window' | translate }}
+
{{ 'calculated-fields.time-window' | translate }}
@if (maxDataPointsPerRollingArg) {
-
{{ 'calculated-fields.limit' | translate }}
+
{{ 'calculated-fields.limit' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts index 482851c59c..8aa61eb1a4 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/panel/calculated-field-argument-panel.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { ChangeDetectorRef, Component, Input, OnInit, output } from '@angular/core'; +import { AfterViewInit, ChangeDetectorRef, Component, Input, OnInit, output, ViewChild } from '@angular/core'; import { TbPopoverComponent } from '@shared/components/popover.component'; import { FormBuilder, FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'; import { charsWithNumRegex, oneSpaceInsideRegex } from '@shared/models/regex.constants'; @@ -41,13 +41,14 @@ import { MINUTE } from '@shared/models/time/time.models'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; +import { EntityAutocompleteComponent } from '@shared/components/entity/entity-autocomplete.component'; @Component({ selector: 'tb-calculated-field-argument-panel', templateUrl: './calculated-field-argument-panel.component.html', styleUrls: ['./calculated-field-argument-panel.component.scss'] }) -export class CalculatedFieldArgumentPanelComponent implements OnInit { +export class CalculatedFieldArgumentPanelComponent implements OnInit, AfterViewInit { @Input() buttonTitle: string; @Input() index: number; @@ -55,9 +56,12 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { @Input() entityId: EntityId; @Input() tenantId: string; @Input() entityName: string; + @Input() entityHasError: boolean; @Input() calculatedFieldType: CalculatedFieldType; @Input() usedArgumentNames: string[]; + @ViewChild('entityAutocomplete') entityAutocomplete: EntityAutocompleteComponent; + argumentsDataApplied = output<{ value: CalculatedFieldArgumentValue, index: number }>(); readonly maxDataPointsPerRollingArg = getCurrentAuthState(this.store).maxDataPointsPerRollingArg; @@ -75,8 +79,8 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { scope: [{ value: AttributeScope.SERVER_SCOPE, disabled: true }, [Validators.required]], }), defaultValue: ['', [Validators.pattern(oneSpaceInsideRegex)]], - limit: [{ value: this.defaultLimit, disabled: !this.maxDataPointsPerRollingArg }], - timeWindow: [MINUTE * 15], + limit: [{ value: this.defaultLimit, disabled: !this.maxDataPointsPerRollingArg }, [Validators.required, Validators.min(1), Validators.max(this.maxDataPointsPerRollingArg)]], + timeWindow: [MINUTE * 15, [Validators.required]], }); argumentTypes: ArgumentType[]; @@ -136,6 +140,12 @@ export class CalculatedFieldArgumentPanelComponent implements OnInit { .filter(type => type !== ArgumentType.Rolling || this.calculatedFieldType === CalculatedFieldType.SCRIPT); } + ngAfterViewInit(): void { + if (this.entityHasError) { + this.entityAutocomplete.selectEntityFormGroup.get('entity').markAsTouched(); + } + } + saveArgument(): void { const { refEntityId, ...restConfig } = this.argumentFormGroup.value; const value = (refEntityId.entityType === ArgumentEntityType.Current ? restConfig : { refEntityId, ...restConfig }) as CalculatedFieldArgumentValue; diff --git a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts index 0c4b696ad1..2042b7fdb6 100644 --- a/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts +++ b/ui-ngx/src/app/modules/home/components/vc/entity-version-create.component.ts @@ -89,7 +89,8 @@ export class EntityVersionCreateComponent extends PageComponent implements OnIni {entityName: this.entityName}), [Validators.required, Validators.pattern(/(?:.|\s)*\S(&:.|\s)*/)]], saveRelations: [false, []], saveAttributes: [true, []], - saveCredentials: [true, []] + saveCredentials: [true, []], + saveCalculatedFields: [true, []] }); } diff --git a/ui-ngx/src/app/shared/import-export/import-export.service.ts b/ui-ngx/src/app/shared/import-export/import-export.service.ts index 6109275d6d..2ad60f0139 100644 --- a/ui-ngx/src/app/shared/import-export/import-export.service.ts +++ b/ui-ngx/src/app/shared/import-export/import-export.service.ts @@ -187,18 +187,8 @@ export class ImportExportService { }); } - public importCalculatedField(entityId: EntityId): Observable { + public openCalculatedFieldImportDialog(): Observable { return this.openImportDialog('calculated-fields.import', 'calculated-fields.file').pipe( - mergeMap((calculatedField: CalculatedField) => { - if (!this.validateImportedCalculatedField({ entityId, ...calculatedField })) { - this.store.dispatch(new ActionNotificationShow( - {message: this.translate.instant('calculated-fields.invalid-file-error'), - type: 'error'})); - throw new Error('Invalid calculated field file'); - } else { - return this.calculatedFieldsService.saveCalculatedField(this.prepareImport({ entityId, ...calculatedField })); - } - }), catchError(() => of(null)), ); } @@ -989,16 +979,6 @@ export class ImportExportService { } } - private validateImportedCalculatedField(calculatedField: CalculatedField): boolean { - const { name, configuration, entityId } = calculatedField; - return isNotEmptyStr(name) - && isDefined(configuration) - && isDefined(entityId?.id) - && !!Object.keys(configuration.arguments).length - && isDefined(configuration.expression) - && isDefined(configuration.output) - } - private validateImportedImage(image: ImageExportData): boolean { return !(!isNotEmptyStr(image.data) || !isNotEmptyStr(image.title) diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index c898342c68..7e553fde5f 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -127,7 +127,7 @@ export const ArgumentTypeTranslations = new Map( export interface CalculatedFieldArgument { refEntityKey: RefEntityKey; defaultValue?: string; - refEntityId?: RefEntityKey; + refEntityId?: RefEntityId; limit?: number; timeWindow?: number; } @@ -138,7 +138,7 @@ export interface RefEntityKey { scope?: AttributeScope; } -export interface RefEntityKey { +export interface RefEntityId { entityType: ArgumentEntityType; id: string; } @@ -563,12 +563,12 @@ export const getCalculatedFieldArgumentsHighlights = ( regex: `\\b${key}\\b`, next: argumentsObj[key].refEntityKey.type === ArgumentType.Rolling ? 'calculatedFieldRollingArgumentValue' - : 'start' + : 'no_regex' })); const calculatedFieldCtxArgumentsHighlightRules = { calculatedFieldCtxArgs: [ dotOperatorHighlightRule, - ...calculatedFieldArgumentsKeys.map(argumentRule => argumentRule.next === 'start' ? {...argumentRule, next: 'calculatedFieldSingleArgumentValue' } : argumentRule), + ...calculatedFieldArgumentsKeys.map(argumentRule => argumentRule.next === 'no_regex' ? {...argumentRule, next: 'calculatedFieldSingleArgumentValue' } : argumentRule), endGroupHighlightRule ] }; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 883acdbf21..295a8ac35e 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -1074,7 +1074,8 @@ "argument-type-required": "Argument type is required.", "max-args": "Maximum number of arguments reached.", "decimals-range": "Decimals by default should be a number between 0 and 15.", - "expression": "Default expression demonstrates how to transform a temperature from Fahrenheit to Celsius." + "expression": "Default expression demonstrates how to transform a temperature from Fahrenheit to Celsius.", + "arguments-entity-not-found": "Argument target entity not found." } }, "confirm-on-exit": { @@ -5570,12 +5571,12 @@ "max-calculated-fields": "Calculated fields per entity maximum number", "max-calculated-fields-range": "Calculated fields per entity maximum number can't be negative", "max-calculated-fields-required": "Calculated fields per entity maximum number is required", - "max-data-points-per-rolling-arg": "Maximum data points number in rolling arguments", - "max-data-points-per-rolling-arg-range": "Maximum data points number in rolling arguments can't be negative", - "max-data-points-per-rolling-arg-required": "Maximum data points number in rolling arguments is required", - "max-arguments-per-cf": "Arguments per calculated field maximum number", - "max-arguments-per-cf-range": "Arguments per calculated field maximum number can't be negative", - "max-arguments-per-cf-required": "Arguments per calculated field maximum number is required", + "max-data-points-per-rolling-arg": "Max data points number in rolling arguments", + "max-data-points-per-rolling-arg-range": "Max data points number in rolling arguments can't be negative", + "max-data-points-per-rolling-arg-required": "Max data points number in rolling arguments is required", + "max-arguments-per-cf": "Arguments per calculated field max number", + "max-arguments-per-cf-range": "Arguments per calculated field max number can't be negative", + "max-arguments-per-cf-required": "Arguments per calculated field max number is required", "max-state-size": "State maximum size in KB", "max-state-size-range": "State maximum size in KB can't be negative", "max-state-size-required": "State maximum size in KB is required", From bdec59af0e9f91b3fd5217d63270041cba4c523b Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 11 Mar 2025 18:36:07 +0200 Subject: [PATCH 042/116] Resolved review comments --- .../entity-debug-settings-button.component.ts | 3 +- .../entity-debug-settings-panel.component.ts | 3 +- .../debug/entity-debug-settings.model.ts | 33 +++++++++++++++++++ .../debug/entity-debug-settings.service.ts | 3 +- .../shared/models/calculated-field.models.ts | 2 +- ui-ngx/src/app/shared/models/entity.models.ts | 16 --------- 6 files changed, 40 insertions(+), 20 deletions(-) create mode 100644 ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts index 99a08494fc..85a90aef63 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-button.component.ts @@ -28,13 +28,14 @@ import { MatButton } from '@angular/material/button'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { BehaviorSubject, of, shareReplay, timer } from 'rxjs'; import { SECOND, MINUTE } from '@shared/models/time/time.models'; -import { AdditionalDebugActionConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { map, switchMap, takeWhile } from 'rxjs/operators'; import { getCurrentAuthState } from '@core/auth/auth.selectors'; import { AppState } from '@core/core.state'; import { Store } from '@ngrx/store'; import { ControlValueAccessor, FormBuilder, NG_VALUE_ACCESSOR } from '@angular/forms'; import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Component({ selector: 'tb-entity-debug-settings-button', diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts index 5fd3613296..1f95a93084 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings-panel.component.ts @@ -32,8 +32,9 @@ import { SECOND } from '@shared/models/time/time.models'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; import { of, shareReplay, timer } from 'rxjs'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; -import { AdditionalDebugActionConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { distinctUntilChanged, map, startWith, switchMap, takeWhile } from 'rxjs/operators'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Component({ selector: 'tb-entity-debug-settings-panel', diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts new file mode 100644 index 0000000000..6560580502 --- /dev/null +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.model.ts @@ -0,0 +1,33 @@ +/// +/// Copyright © 2016-2025 The Thingsboard Authors +/// +/// Licensed under the Apache License, Version 2.0 (the "License"); +/// you may not use this file except in compliance with the License. +/// You may obtain a copy of the License at +/// +/// http://www.apache.org/licenses/LICENSE-2.0 +/// +/// Unless required by applicable law or agreed to in writing, software +/// distributed under the License is distributed on an "AS IS" BASIS, +/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +/// See the License for the specific language governing permissions and +/// limitations under the License. +/// + +import { EntityDebugSettings } from '@shared/models/entity.models'; + +export interface AdditionalDebugActionConfig void> { + action: Action; + title: string; +} + +export interface EntityDebugSettingPanelConfig { + debugSettings: EntityDebugSettings; + debugConfig: { + maxDebugModeDuration: number; + debugLimitsConfiguration: string; + entityLabel?: string; + additionalActionConfig?: AdditionalDebugActionConfig; + } + onSettingsAppliedFn: (settings: EntityDebugSettings) => void; +} diff --git a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts index c53bc5b777..873d8f0f3f 100644 --- a/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts +++ b/ui-ngx/src/app/modules/home/components/entity/debug/entity-debug-settings.service.ts @@ -16,10 +16,11 @@ import { Injectable, Optional, Renderer2, ViewContainerRef } from '@angular/core'; import { EntityDebugSettingsPanelComponent } from '@home/components/entity/debug/entity-debug-settings-panel.component'; -import { EntityDebugSettingPanelConfig, EntityDebugSettings } from '@shared/models/entity.models'; +import { EntityDebugSettings } from '@shared/models/entity.models'; import { TbPopoverService } from '@shared/components/popover.service'; import { TranslateService } from '@ngx-translate/core'; import { DurationLeftPipe } from '@shared/pipe/duration-left.pipe'; +import { EntityDebugSettingPanelConfig } from '@home/components/entity/debug/entity-debug-settings.model'; @Injectable() export class EntityDebugSettingsService { diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index 7083ce7ae0..c7b37e46f5 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -15,7 +15,6 @@ /// import { - AdditionalDebugActionConfig, HasEntityDebugSettings, HasTenantId, HasVersion @@ -34,6 +33,7 @@ import { dotOperatorHighlightRule, endGroupHighlightRule } from '@shared/models/ace/ace.models'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; export interface CalculatedField extends Omit, 'label'>, HasVersion, HasEntityDebugSettings, HasTenantId, ExportableEntity { configuration: CalculatedFieldConfiguration; diff --git a/ui-ngx/src/app/shared/models/entity.models.ts b/ui-ngx/src/app/shared/models/entity.models.ts index 87536fdc54..5aa526b583 100644 --- a/ui-ngx/src/app/shared/models/entity.models.ts +++ b/ui-ngx/src/app/shared/models/entity.models.ts @@ -203,25 +203,9 @@ export interface EntityDebugSettings { allEnabledUntil?: number; } -export interface EntityDebugSettingPanelConfig { - debugSettings: EntityDebugSettings; - debugConfig: { - maxDebugModeDuration: number; - debugLimitsConfiguration: string; - entityLabel?: string; - additionalActionConfig?: AdditionalDebugActionConfig; - } - onSettingsAppliedFn: (settings: EntityDebugSettings) => void; -} - export interface EntityTestScriptResult { output: string; error: string; } -export interface AdditionalDebugActionConfig void> { - action: Action; - title: string; -} - export type VersionedEntity = EntityInfoData & HasVersion | RuleChainMetaData; From 9570abe2ce8364ece33cec155ca6e1c16aefd977 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Tue, 11 Mar 2025 18:55:07 +0200 Subject: [PATCH 043/116] Naming improvement --- .../action/mobile-action-editor.component.html | 2 +- .../action/mobile-action-editor.component.ts | 10 +++++----- .../common/action/mobile-action-editor.models.ts | 15 ++++++++------- .../home/components/widget/widget.component.ts | 4 ++-- ui-ngx/src/app/shared/models/widget.models.ts | 8 ++++---- .../src/assets/locale/locale.constant-en_US.json | 2 +- 6 files changed, 21 insertions(+), 20 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html index c21595eea9..c3194676cf 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/mobile-action-editor.component.html @@ -36,7 +36,7 @@
- + processQrCodeFunction; export const getDefaultProcessLocationFunction = () => processLocationFunction; -export const getDefaultProvisioningSuccessFunction = () => provisioningSuccessFunction; +export const getDefaultProvisionSuccessFunction = () => provisionSuccessFunction; export const getDefaultGetLocationFunction = () => getLocationFunctionTemplate; @@ -285,8 +286,8 @@ export const getDefaultHandleEmptyResultFunction = (type: WidgetMobileActionType case WidgetMobileActionType.takeScreenshot: message = 'Take screenshot action was cancelled!'; break; - case WidgetMobileActionType.provisionDevice: - message = 'Provisioning device was not invoked!'; + case WidgetMobileActionType.deviceProvision: + message = 'Device provision was not invoked!'; break; } return handleEmptyResultFunctionTemplate.replace('--MESSAGE--', message); @@ -319,7 +320,7 @@ export const getDefaultHandleErrorFunction = (type: WidgetMobileActionType): TbF case WidgetMobileActionType.takeScreenshot: title = 'Failed to take screenshot'; break; - case WidgetMobileActionType.provisionDevice: + case WidgetMobileActionType.deviceProvision: title = 'Failed to make device provision'; break; } diff --git a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts index ca11c2f4e0..3d20bcbd35 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget.component.ts @@ -1203,7 +1203,7 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, case WidgetMobileActionType.scanQrCode: case WidgetMobileActionType.getLocation: case WidgetMobileActionType.takeScreenshot: - case WidgetMobileActionType.provisionDevice: + case WidgetMobileActionType.deviceProvision: argsObservable = of([]); break; case WidgetMobileActionType.mapDirection: @@ -1293,7 +1293,7 @@ export class WidgetComponent extends PageComponent implements OnInit, OnChanges, ); } break; - case WidgetMobileActionType.provisionDevice: + case WidgetMobileActionType.deviceProvision: const deviceName = actionResult.deviceName; if (isNotEmptyTbFunction(mobileAction.handleProvisionSuccessFunction)) { compileTbFunction(this.http, mobileAction.handleProvisionSuccessFunction, 'deviceName', '$event', 'widgetContext', 'entityId', diff --git a/ui-ngx/src/app/shared/models/widget.models.ts b/ui-ngx/src/app/shared/models/widget.models.ts index 132c82cfd1..4461758c85 100644 --- a/ui-ngx/src/app/shared/models/widget.models.ts +++ b/ui-ngx/src/app/shared/models/widget.models.ts @@ -588,7 +588,7 @@ export enum WidgetMobileActionType { makePhoneCall = 'makePhoneCall', getLocation = 'getLocation', takeScreenshot = 'takeScreenshot', - provisionDevice = 'provisionDevice', + deviceProvision = 'deviceProvision', } export const widgetActionTypes = Object.keys(WidgetActionType) as WidgetActionType[]; @@ -616,7 +616,7 @@ export const widgetMobileActionTypeTranslationMap = new Map { result?: T; diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index 4ccb6ed8f5..e71b2f6930 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -6536,7 +6536,7 @@ "URL": "URL", "url-required": "URL is required.", "mobile": { - "provision-device": "Provision device", + "device-provision": "Device provision", "action-type": "Mobile action type", "select-action-type": "Select mobile action type", "action-type-required": "Mobile action type is required", From 12d07f1cc8220a09a67941e4ebee5ab8c3a6033d Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Tue, 11 Mar 2025 19:23:56 +0200 Subject: [PATCH 044/116] UI: Map - introduce reference vector layers. --- ui-ngx/package.json | 2 + .../widget/lib/maps/leaflet/leaflet-tb.ts | 21 +- .../components/widget/lib/maps/map-layer.ts | 116 +- .../home/components/widget/lib/maps/map.scss | 8 + .../common/map/map-layer-row.component.ts | 3 +- .../map-layer-settings-panel.component.html | 11 + .../map/map-layer-settings-panel.component.ts | 9 +- .../shared/models/widget/maps/map.models.ts | 22 +- .../assets/locale/locale.constant-en_US.json | 6 + .../openstreetmap_hybrid_reference_style.json | 25800 +++++++ .../world_edition_hybrid_reference_style.json | 57837 ++++++++++++++++ ui-ngx/src/typings/leaflet-extend-tb.d.ts | 1 + ui-ngx/yarn.lock | 228 +- 13 files changed, 84033 insertions(+), 31 deletions(-) create mode 100644 ui-ngx/src/assets/map/openstreetmap_hybrid_reference_style.json create mode 100644 ui-ngx/src/assets/map/world_edition_hybrid_reference_style.json diff --git a/ui-ngx/package.json b/ui-ngx/package.json index b2e2dc18c3..1536858de8 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -28,6 +28,7 @@ "@flowjs/ngx-flow": "18.0.1", "@geoman-io/leaflet-geoman-free": "2.17.0", "@iplab/ngx-color-picker": "^18.0.1", + "@maplibre/maplibre-gl-leaflet": "^0.0.22", "@mat-datetimepicker/core": "~14.0.0", "@mdi/svg": "^7.4.47", "@messageformat/core": "^3.4.0", @@ -64,6 +65,7 @@ "leaflet.gridlayer.googlemutant": "0.14.1", "leaflet.markercluster": "1.5.3", "libphonenumber-js": "^1.11.15", + "maplibre-gl": "^4.7.1", "marked": "~12.0.2", "moment": "^2.30.1", "moment-timezone": "^0.5.45", diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts index 06d49d0343..df02c46482 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts @@ -17,6 +17,7 @@ import L, { TB } from 'leaflet'; import { guid, isNotEmptyStr } from '@core/utils'; import 'leaflet-providers'; +import '@maplibre/maplibre-gl-leaflet'; import '@geoman-io/leaflet-geoman-free'; import 'leaflet.markercluster'; import { MatIconRegistry } from '@angular/material/icon'; @@ -211,15 +212,19 @@ class LayersControl extends SidebarPaneControl { input.on('click', (e: JQuery.MouseEventBase) => { e.stopPropagation(); - layers.forEach((other) => { - if (other.layer === layerData.layer) { - map.addLayer(other.layer); - map.attributionControl.setPrefix(other.attributionPrefix); - } else { - map.removeLayer(other.layer); + if (!map.hasLayer(layerData.layer)) { + map.addLayer(layerData.layer); + map.attributionControl.setPrefix(layerData.attributionPrefix); + if (layerData.onAdd) { + layerData.onAdd(); } - }); - map.fire('baselayerchange', { layer: layerData.layer }); + layers.forEach((other) => { + if (other.layer !== layerData.layer) { + map.removeLayer(other.layer); + } + }); + map.fire('baselayerchange', { layer: layerData.layer }); + } }); item.on('dblclick', (e) => { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts index 304100828b..87ca69034f 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts @@ -26,17 +26,34 @@ import { HereMapLayerSettings, MapLayerSettings, MapProvider, - OpenStreetMapLayerSettings, + OpenStreetMapLayerSettings, ReferenceLayerType, TencentMapLayerSettings } from '@shared/models/widget/maps/map.models'; import { WidgetContext } from '@home/models/widget-component.models'; import { DeepPartial } from '@shared/models/common'; import { mergeDeep } from '@core/utils'; -import { Observable, of, switchMap } from 'rxjs'; +import { Observable, of, shareReplay, switchMap } from 'rxjs'; import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe'; import L from 'leaflet'; import { catchError, map } from 'rxjs/operators'; import { ResourcesService } from '@core/services/resources.service'; +import { StyleSpecification, VectorSourceSpecification } from '@maplibre/maplibre-gl-style-spec'; +import { ResourceType } from 'maplibre-gl'; + +const referenceLayerStyleUrlMap = new Map( + [ + [ReferenceLayerType.openstreetmap_hybrid, '/assets/map/openstreetmap_hybrid_reference_style.json'], + [ReferenceLayerType.world_edition_hybrid, '/assets/map/world_edition_hybrid_reference_style.json'] + ] +); + +const referenceLayerCache = new Map>(); + +interface TbMapLayerData { + layer: L.Layer; + attribution: boolean; + onAdd?: () => void; +} export abstract class TbMapLayer { @@ -65,19 +82,23 @@ export abstract class TbMapLayer { } public loadLayer(theMap: L.Map): Observable { - return this.createLayer().pipe( - switchMap((layer) => { - if (layer) { - return this.createLayer().pipe( - map((mini) => { - if (mini) { - const attribution = layer.getAttribution(); - const attributionPrefix = attribution ? theMap.attributionControl.options.prefix as string : null; + return this.generateLayer().pipe( + switchMap((layerData) => { + if (layerData) { + return this.generateLayer().pipe( + map((miniLayerData) => { + if (miniLayerData) { + const attributionPrefix = layerData.attribution ? theMap.attributionControl.options.prefix as string : null; return { title: this.title(), attributionPrefix: attributionPrefix, - layer, - mini + layer: layerData.layer, + mini: miniLayerData.layer, + onAdd: () => { + if (layerData.onAdd) { + layerData.onAdd(); + } + } }; } else { return null; @@ -91,6 +112,77 @@ export abstract class TbMapLayer { ); } + private generateLayer(): Observable { + return this.createLayer().pipe( + switchMap((baseLayer) => { + if (baseLayer) { + if (this.settings.referenceLayer) { + return this.loadReferenceLayer(this.settings.referenceLayer).pipe( + map((referenceLayer) => { + if (referenceLayer) { + const layer = L.featureGroup(); + baseLayer.addTo(layer); + referenceLayer.addTo(layer); + return { + layer, + attribution: !!baseLayer.getAttribution() || !!referenceLayer.getAttribution(), + onAdd: () => { + (referenceLayer as any)._update(); + } + }; + } else { + return { + layer: baseLayer, + attribution: !!baseLayer.getAttribution() + }; + } + })); + } else { + return of({ + layer: baseLayer, + attribution: !!baseLayer.getAttribution() + }); + } + } else { + return of(null); + } + } + )); + } + + private loadReferenceLayer(referenceLayer: ReferenceLayerType): Observable { + let spec$ = referenceLayerCache.get(referenceLayer); + if (!spec$) { + const styleUrl = referenceLayerStyleUrlMap.get(referenceLayer); + spec$ = this.ctx.http.get(styleUrl).pipe( + shareReplay({ + bufferSize: 1, + refCount: true + }) + ); + referenceLayerCache.set(referenceLayer, spec$); + } + return spec$.pipe( + map(spec => { + const sourceSpec = (spec.sources['esri'] as VectorSourceSpecification); + const tileUrl = sourceSpec.url; + const attribution = sourceSpec.attribution; + const transformRequest = (url: string, resourceType: ResourceType) => { + if (resourceType === 'Tile') { + url = tileUrl + '/' + url; + } + return {url} + } + const gl = L.maplibreGL({ + style: spec, + transformRequest + }); + gl.options.attribution = attribution; + return gl; + }) + ); + } + private title(): string { const customTranslate = this.ctx.$injector.get(CustomTranslatePipe); if (this.settings.label) { diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss index 592610f8b2..985bdc17f5 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map.scss @@ -35,6 +35,10 @@ div.tb-widget .tb-widget-content.tb-no-interaction { .tb-map-container { flex-direction: column; + .leaflet-gl-layer.maplibregl-map { + position: relative; + z-index: 1; + } } .tb-map-layout { @@ -47,6 +51,10 @@ div.tb-widget .tb-widget-content.tb-no-interaction { .tb-map { position: relative; flex: 1; + .leaflet-control-attribution { + font-size: 0.6rem; + background: rgba(255,255,255,0.5); + } &.leaflet-touch { .leaflet-bar { border: 1px solid rgba(0,0,0,0.38); diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts index 7112a0c3c2..392c9f9565 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-row.component.ts @@ -123,7 +123,8 @@ export class MapLayerRowComponent implements ControlValueAccessor, OnInit { provider: [null, [Validators.required]], layerType: [null, [Validators.required]], tileUrl: [null, [Validators.required]], - apiKey: [null, [Validators.required]] + apiKey: [null, [Validators.required]], + referenceLayer: [null, []] }); this.layerFormGroup.valueChanges.pipe( takeUntilDestroyed(this.destroyRef) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-settings-panel.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-settings-panel.component.html index c30033f7e1..cf4c4b90c4 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-settings-panel.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/map-layer-settings-panel.component.html @@ -82,6 +82,17 @@
+
+
widgets.maps.layer.reference.reference-layer
+ + + {{ 'widgets.maps.layer.reference.no-layer' | translate }} + + {{ referenceLayerTypeTranslationMap.get(layer) | translate }} + + + +
Date: Wed, 12 Mar 2025 11:59:45 +0200 Subject: [PATCH 053/116] Added help popup width --- .../components/dialog/calculated-field-dialog.component.html | 1 + .../calculated-field-script-test-dialog.component.html | 1 + ui-ngx/src/app/shared/components/js-func.component.html | 2 +- ui-ngx/src/app/shared/components/js-func.component.ts | 2 ++ 4 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html index 471c722145..813f6b1b4c 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.html @@ -102,6 +102,7 @@ [scriptLanguage]="ScriptLanguage.TBEL" [highlightRules]="argumentsHighlightRules$ | async" [editorCompleter]="argumentsEditorCompleter$ | async" + [helpPopupStyle]="{ width: '1200px' }" helpId="calculated-field/expression_fn" >
{{ 'api-usage.tbel' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html index 6859ff6dab..942d9484b5 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.html @@ -44,6 +44,7 @@ [highlightRules]="data.argumentsHighlightRules" [scriptLanguage]="ScriptLanguage.TBEL" [editorCompleter]="data.argumentsEditorCompleter" + [helpPopupStyle]="{ width: '1200px' }" resultType="object" helpId="calculated-field/expression_fn" /> diff --git a/ui-ngx/src/app/shared/components/js-func.component.html b/ui-ngx/src/app/shared/components/js-func.component.html index 3155669f29..07f6dfe1b4 100644 --- a/ui-ngx/src/app/shared/components/js-func.component.html +++ b/ui-ngx/src/app/shared/components/js-func.component.html @@ -41,7 +41,7 @@ {{'js-func.tidy' | translate }} -
+
; + @Input() helpPopupStyle: Record = {}; + @Input() @coerceBoolean() disableUndefinedCheck = false; From 52c04a4e02f59a94d4061ad3f5b7daf6fe8fe3ee Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 12 Mar 2025 12:00:19 +0200 Subject: [PATCH 054/116] refactored getOwnerName --- .../thingsboard/server/edqs/repo/TenantRepo.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/common/edqs/src/main/java/org/thingsboard/server/edqs/repo/TenantRepo.java b/common/edqs/src/main/java/org/thingsboard/server/edqs/repo/TenantRepo.java index 59255b11cc..ab7fb3acff 100644 --- a/common/edqs/src/main/java/org/thingsboard/server/edqs/repo/TenantRepo.java +++ b/common/edqs/src/main/java/org/thingsboard/server/edqs/repo/TenantRepo.java @@ -422,19 +422,19 @@ public class TenantRepo { } public String getOwnerName(EntityId ownerId) { - if (ownerId == null || (EntityType.CUSTOMER.equals(ownerId.getEntityType()) && CustomerId.NULL_UUID.equals(ownerId.getId()))) { - ownerId = tenantId; + if (ownerId == null || (ownerId.getEntityType() == EntityType.CUSTOMER && ownerId.isNullUid())) { + return getOwnerEntityName(tenantId); } - return getEntityName(ownerId); + return getOwnerEntityName(ownerId); } - private String getEntityName(EntityId entityId) { + private String getOwnerEntityName(EntityId entityId) { EntityType entityType = entityId.getEntityType(); - if (entityType == EntityType.TENANT && entityId.getId().equals(TenantId.NULL_UUID)) { - return ""; - } return switch (entityType) { - case CUSTOMER, TENANT -> getEntityMap(entityType).get(entityId.getId()).getFields().getName(); + case CUSTOMER, TENANT -> { + EntityFields fields = getEntityMap(entityType).get(entityId.getId()).getFields(); + yield fields != null ? fields.getName() : ""; + } default -> throw new RuntimeException("Unsupported entity type: " + entityType); }; } From fdfb9264ad7738a45d08df538bb860a3e9849e01 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 12 Mar 2025 12:03:15 +0200 Subject: [PATCH 055/116] UI: Refactoring --- ui-ngx/src/app/shared/components/nav-tree.component.ts | 8 ++------ ui-ngx/src/typings/jquery.jstree.typings.d.ts | 1 + 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ui-ngx/src/app/shared/components/nav-tree.component.ts b/ui-ngx/src/app/shared/components/nav-tree.component.ts index 60405613fb..5b698a37d3 100644 --- a/ui-ngx/src/app/shared/components/nav-tree.component.ts +++ b/ui-ngx/src/app/shared/components/nav-tree.component.ts @@ -52,10 +52,6 @@ export interface NavTreeEditCallbacks { clearSearch?: () => void; } -interface JSTreeEventDataWithAction extends JSTreeEventData { - action: string; -} - export type NodesCallback = (nodes: NavTreeNode[]) => void; export type LoadNodesCallback = (node: NavTreeNode, cb: NodesCallback) => void; export type NodeSearchCallback = (searchText: string, node: NavTreeNode) => boolean; @@ -153,9 +149,9 @@ export class NavTreeComponent implements OnInit { this.treeElement = $('.tb-nav-tree-container', this.elementRef.nativeElement).jstree(config); - this.treeElement.on('changed.jstree', (e: any, data: JSTreeEventDataWithAction) => { - const node: NavTreeNode = data.instance.get_selected(true)[0]; + this.treeElement.on('changed.jstree', (e: any, data) => { if (this.onNodeSelected && data.action !== 'ready') { + const node: NavTreeNode = data.instance.get_selected(true)[0]; this.ngZone.run(() => this.onNodeSelected(node, e as Event)); } }); diff --git a/ui-ngx/src/typings/jquery.jstree.typings.d.ts b/ui-ngx/src/typings/jquery.jstree.typings.d.ts index 0aa6a0b92e..933a9c60d5 100644 --- a/ui-ngx/src/typings/jquery.jstree.typings.d.ts +++ b/ui-ngx/src/typings/jquery.jstree.typings.d.ts @@ -27,6 +27,7 @@ interface JQuery { interface JSTreeEventData { instance: JSTree; + action: string; } interface JSTreeModelEventData extends JSTreeEventData { From 6d565b4ccbd49dcee758c1a25396f1e63b65c68d Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Wed, 12 Mar 2025 12:27:20 +0200 Subject: [PATCH 056/116] Fix method getEntityDataInfo in VersionController --- .../service/sync/vc/DefaultEntitiesVersionControlService.java | 3 +-- .../thingsboard/server/common/data/sync/vc/EntityDataInfo.java | 1 + 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java index 8ef6465d4b..3029e0be70 100644 --- a/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java +++ b/application/src/main/java/org/thingsboard/server/service/sync/vc/DefaultEntitiesVersionControlService.java @@ -500,10 +500,9 @@ public class DefaultEntitiesVersionControlService implements EntitiesVersionCont @Override public ListenableFuture getEntityDataInfo(User user, EntityId entityId, String versionId) { return Futures.transform(gitServiceQueue.getEntity(user.getTenantId(), versionId, entityId), - entity -> new EntityDataInfo(entity.hasRelations(), entity.hasAttributes(), entity.hasCredentials()), MoreExecutors.directExecutor()); + entity -> new EntityDataInfo(entity.hasRelations(), entity.hasAttributes(), entity.hasCredentials(), entity.hasCalculatedFields()), MoreExecutors.directExecutor()); } - @Override public ListenableFuture> listBranches(TenantId tenantId) { return gitServiceQueue.listBranches(tenantId); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataInfo.java b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataInfo.java index 0b8f392472..d55a575a75 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataInfo.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/sync/vc/EntityDataInfo.java @@ -26,4 +26,5 @@ public class EntityDataInfo { boolean hasRelations; boolean hasAttributes; boolean hasCredentials; + boolean hasCalculatedFields; } From ae02d43142e425db3713adef5377c0cd099fe554 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Wed, 12 Mar 2025 12:29:00 +0200 Subject: [PATCH 057/116] moved check to validator --- .../CalculatedFieldEntityMessageProcessor.java | 2 ++ .../service/entitiy/queue/DefaultTbQueueService.java | 8 -------- .../org/thingsboard/server/dao/service/DataValidator.java | 4 ++++ 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java index 8767784a28..a185b71d56 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldEntityMessageProcessor.java @@ -289,6 +289,8 @@ public class CalculatedFieldEntityMessageProcessor extends AbstractContextAwareM if (state.isSizeOk()) { if (!calculationResult.isEmpty()) { cfService.pushMsgToRuleEngine(tenantId, entityId, calculationResult, cfIdList, callback); + } else { + callback.onSuccess(); } if (DebugModeUtil.isDebugAllAvailable(ctx.getCalculatedField())) { systemContext.persistCalculatedFieldDebugEvent(tenantId, ctx.getCfId(), entityId, state.getArguments(), tbMsgId, tbMsgType, JacksonUtil.writeValueAsString(calculationResult.getResult()), null); diff --git a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java index 44c5182423..0d4cc26ce7 100644 --- a/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java +++ b/application/src/main/java/org/thingsboard/server/service/entitiy/queue/DefaultTbQueueService.java @@ -19,7 +19,6 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.thingsboard.server.cluster.TbClusterService; -import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.TenantProfile; import org.thingsboard.server.common.data.id.QueueId; import org.thingsboard.server.common.data.id.TenantId; @@ -57,7 +56,6 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb oldQueue = queueService.findQueueById(queue.getTenantId(), queue.getId()); } - checkQueueName(queue.getName()); Queue savedQueue = queueService.saveQueue(queue); createTopicsIfNeeded(savedQueue, oldQueue); tbClusterService.onQueuesUpdate(List.of(savedQueue)); @@ -183,10 +181,4 @@ public class DefaultTbQueueService extends AbstractTbEntityService implements Tb } } - private void checkQueueName(String queueName) { - if (DataConstants.CF_QUEUE_NAME.equals(queueName) || DataConstants.CF_STATES_QUEUE_NAME.equals(queueName)) { - throw new IllegalArgumentException(String.format("The queue name '%s' is not allowed. This name is reserved for internal use. Please choose a different name.", queueName)); - } - } - } diff --git a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java index ba88d446d9..9f1f583108 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java +++ b/dao/src/main/java/org/thingsboard/server/dao/service/DataValidator.java @@ -21,6 +21,7 @@ import org.apache.commons.io.FileUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.thingsboard.server.common.data.BaseData; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.StringUtils; import org.thingsboard.server.common.data.id.EntityId; @@ -158,6 +159,9 @@ public abstract class DataValidator> { protected static void validateQueueName(String name) { validateQueueNameOrTopic(name, NAME); + if (DataConstants.CF_QUEUE_NAME.equals(name) || DataConstants.CF_STATES_QUEUE_NAME.equals(name)) { + throw new DataValidationException(String.format("The queue name '%s' is not allowed. This name is reserved for internal use. Please choose a different name.", name)); + } } protected static void validateQueueTopic(String topic) { From 2d637558ae59d93bb7c5efc2f7c7bbe94510bc78 Mon Sep 17 00:00:00 2001 From: mpetrov Date: Wed, 12 Mar 2025 13:07:46 +0200 Subject: [PATCH 058/116] Added support for arrays result in events table --- .../modules/home/components/event/event-table-config.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts index 56a17cc7ae..5d770fed3b 100644 --- a/ui-ngx/src/app/modules/home/components/event/event-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/event/event-table-config.ts @@ -478,7 +478,12 @@ export class EventTableConfig extends EntityTableConfig { } if (contentType === ContentType.JSON && sortKeys) { try { - content = JSON.stringify(sortObjectKeys(JSON.parse(content))); + const parsedContent = JSON.parse(content); + if (Array.isArray(parsedContent)) { + content = JSON.stringify(parsedContent.map(item => item && typeof item === 'object' ? sortObjectKeys(item) : item)); + } else { + content = JSON.stringify(sortObjectKeys(parsedContent)); + } } catch (e) {} } this.dialog.open(EventContentDialogComponent, { From e81e248bf2d227901e56475e64e699ce68a1bb56 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 12 Mar 2025 13:21:06 +0200 Subject: [PATCH 059/116] UI: Fixed entity autocomplete --- .../shared/components/entity/entity-autocomplete.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts index 848550a94b..ac8054283a 100644 --- a/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts +++ b/ui-ngx/src/app/shared/components/entity/entity-autocomplete.component.ts @@ -391,7 +391,7 @@ export class EntityAutocompleteComponent implements ControlValueAccessor, OnInit private updateView(value: string | EntityId | null, entity: BaseData | null) { if (!isEqual(this.modelValue, value)) { this.modelValue = value; - this.entityURL = !entity ? '' : getEntityDetailsPageURL(entity.id.id, entity.id.entityType as EntityType); + this.entityURL = (typeof entity === 'string' || !entity) ? '' : getEntityDetailsPageURL(entity.id.id, entity.id.entityType as EntityType); this.propagateChange(this.modelValue); this.entityChanged.emit(entity); } From 3c0bedf5f3d577f53e38076198cd6d437c28e361 Mon Sep 17 00:00:00 2001 From: Andrii Shvaika Date: Wed, 12 Mar 2025 13:30:46 +0200 Subject: [PATCH 060/116] Remove ENV SPRING_DATASOURCE_PASSWORD=postgres from docker files --- msa/tb/docker-cassandra/Dockerfile | 1 - msa/tb/docker-postgres/Dockerfile | 1 - 2 files changed, 2 deletions(-) diff --git a/msa/tb/docker-cassandra/Dockerfile b/msa/tb/docker-cassandra/Dockerfile index 9c49ffe2f9..20a0d8cf7a 100644 --- a/msa/tb/docker-cassandra/Dockerfile +++ b/msa/tb/docker-cassandra/Dockerfile @@ -29,7 +29,6 @@ ENV CASSANDRA_DATA=/data/cassandra ENV SPRING_DRIVER_CLASS_NAME=org.postgresql.Driver ENV SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard ENV SPRING_DATASOURCE_USERNAME=${pkg.user} -ENV SPRING_DATASOURCE_PASSWORD=postgres ENV CASSANDRA_HOST=localhost ENV CASSANDRA_PORT=9042 diff --git a/msa/tb/docker-postgres/Dockerfile b/msa/tb/docker-postgres/Dockerfile index f9e36ed61e..7c66d626c7 100644 --- a/msa/tb/docker-postgres/Dockerfile +++ b/msa/tb/docker-postgres/Dockerfile @@ -29,7 +29,6 @@ ENV PATH=$PATH:/usr/lib/postgresql/$PG_MAJOR/bin ENV SPRING_DRIVER_CLASS_NAME=org.postgresql.Driver ENV SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard ENV SPRING_DATASOURCE_USERNAME=${pkg.user} -ENV SPRING_DATASOURCE_PASSWORD=postgres ENV PGLOG=/var/log/postgres From be9e89955adc16ef99f03e1be3b480d806f949e9 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Wed, 12 Mar 2025 13:47:03 +0200 Subject: [PATCH 061/116] UI: Fixed icon close button position --- .../app/shared/components/string-autocomplete.component.html | 2 +- ui-ngx/src/app/shared/components/unit-input.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui-ngx/src/app/shared/components/string-autocomplete.component.html b/ui-ngx/src/app/shared/components/string-autocomplete.component.html index 459e41fdd8..8a9a1a38d0 100644 --- a/ui-ngx/src/app/shared/components/string-autocomplete.component.html +++ b/ui-ngx/src/app/shared/components/string-autocomplete.component.html @@ -24,7 +24,7 @@ [matAutocomplete]="optionsAutocomplete">
@@ -361,7 +376,12 @@ px - +
widgets.maps.data-layer.fill-color
- +
widgets.maps.data-layer.stroke
@@ -388,7 +413,12 @@ px - +
diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html index 0a78698f0f..0ee3b1de37 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.html @@ -30,5 +30,9 @@
- + diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts index 14e80e4fd2..4400c5a151 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/map/marker-shape-settings.component.ts @@ -49,6 +49,8 @@ import { coerceBoolean } from '@shared/decorators/coercion'; import { MarkerIconShapesComponent } from '@home/components/widget/lib/settings/common/map/marker-icon-shapes.component'; +import { MapSettingsContext } from '@home/components/widget/lib/settings/common/map/map-settings.component.models'; +import { DatasourceType } from '@shared/models/widget.models'; @Component({ selector: 'tb-marker-shape-settings', @@ -69,6 +71,18 @@ export class MarkerShapeSettingsComponent implements ControlValueAccessor, OnIni @Input() disabled: boolean; + @Input() + context: MapSettingsContext; + + @Input() + dsType: DatasourceType; + + @Input() + dsEntityAliasId: string; + + @Input() + dsDeviceId: string; + @Input() markerType: MarkerType; diff --git a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts index 06083f4298..1884e86215 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/map.models.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/map.models.ts @@ -41,7 +41,7 @@ import { Observable, Observer, of, switchMap } from 'rxjs'; import { map } from 'rxjs/operators'; import { ImagePipe } from '@shared/pipe/image.pipe'; import { MarkerIconContainer, MarkerShape } from '@shared/models/widget/maps/marker-shape.models'; -import { DateFormatSettings, simpleDateFormat } from '@shared/models/widget-settings.models'; +import { ColorRange, DateFormatSettings, simpleDateFormat } from '@shared/models/widget-settings.models'; export enum MapType { geoMap = 'geoMap', @@ -233,12 +233,15 @@ export enum MarkerType { export enum DataLayerColorType { constant = 'constant', + range = 'range', function = 'function' } export interface DataLayerColorSettings { type: DataLayerColorType; color: string; + rangeKey?: DataKey; + range?: ColorRange[]; colorFunction?: TbFunction; } diff --git a/ui-ngx/src/assets/locale/locale.constant-en_US.json b/ui-ngx/src/assets/locale/locale.constant-en_US.json index eede6bb27e..eacc85992d 100644 --- a/ui-ngx/src/assets/locale/locale.constant-en_US.json +++ b/ui-ngx/src/assets/locale/locale.constant-en_US.json @@ -7979,7 +7979,11 @@ "stroke": "Stroke", "color-settings": "Color settings", "color-type-constant": "Constant", + "color-type-range": "Range", "color-type-function": "Function", + "color-range-source-key": "Color range source key", + "color-range-source-key-required": "Color range source key is required", + "color-range": "Color range", "color-function": "Color function", "label": "Label", "tooltip": "Tooltip", From 37192de5ef8a9d73a099d6611d01330ac4cad505 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 13 Mar 2025 13:04:09 +0200 Subject: [PATCH 071/116] fixed missed "title" entity field subscription --- .../thingsboard/server/common/data/edqs/fields/EntityFields.java | 1 + 1 file changed, 1 insertion(+) diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/edqs/fields/EntityFields.java b/common/data/src/main/java/org/thingsboard/server/common/data/edqs/fields/EntityFields.java index 532c4a92ac..1b0975542c 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/edqs/fields/EntityFields.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/edqs/fields/EntityFields.java @@ -148,6 +148,7 @@ public interface EntityFields { default String getAsString(String key) { return switch (key) { case "createdTime" -> Long.toString(getCreatedTime()); + case "title" -> getName(); case "type" -> getType(); case "label" -> getLabel(); case "additionalInfo" -> getAdditionalInfo(); From 09cff3ae5c6702873a70080bbca2aee5921db07c Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 13 Mar 2025 13:32:16 +0200 Subject: [PATCH 072/116] UI: Help for get dashboard state id aciton --- ...t-value-action-settings-panel.component.ts | 2 ++ .../parse_value_get_dashboard_state_id_fn.md | 33 +++++++++++++++++++ 2 files changed, 35 insertions(+) create mode 100644 ui-ngx/src/assets/help/en_US/widget/config/parse_value_get_dashboard_state_id_fn.md diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts index 1d1df6a8d5..9f85e9dd85 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/settings/common/action/get-value-action-settings-panel.component.ts @@ -171,6 +171,8 @@ export class GetValueActionSettingsPanelComponent extends PageComponent implemen const action: GetValueAction = this.getValueSettingsFormGroup.get('action').value; if (action === GetValueAction.GET_DASHBOARD_STATE_OBJECT) { return 'widget/config/parse_value_get_dashboard_state_object_fn'; + } else if (action === GetValueAction.GET_DASHBOARD_STATE) { + return 'widget/config/parse_value_get_dashboard_state_id_fn'; } return 'widget/lib/rpc/parse_value_fn'; } diff --git a/ui-ngx/src/assets/help/en_US/widget/config/parse_value_get_dashboard_state_id_fn.md b/ui-ngx/src/assets/help/en_US/widget/config/parse_value_get_dashboard_state_id_fn.md new file mode 100644 index 0000000000..3a580b4136 --- /dev/null +++ b/ui-ngx/src/assets/help/en_US/widget/config/parse_value_get_dashboard_state_id_fn.md @@ -0,0 +1,33 @@ +#### Parse value function + +
+
+ +*function (data): boolean* + +A JavaScript function that converts the current dashboard state id into a boolean value. + +**Parameters:** + +
    +
  • data: string - the current dashboard state id. +
  • +
+ +**Returns:** + +`true` if the widget should be in an activated state, `false` otherwise. + +
+ +##### Examples + +* Check if the current dashboard state id is "default": + +```javascript +return data === 'default' ? true : false; +{:copy-code} +``` + +
+
From 8c6497d773beac877b12ac46dee99d23949be8fc Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 13 Mar 2025 14:36:40 +0200 Subject: [PATCH 073/116] fixed relation created for gateway devices --- .../server/service/transport/DefaultTransportApiService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java index 2c8c942ba3..7fee411704 100644 --- a/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java +++ b/application/src/main/java/org/thingsboard/server/service/transport/DefaultTransportApiService.java @@ -351,7 +351,7 @@ public class DefaultTransportApiService implements TransportApiService { device.setAdditionalInfo(additionalInfo); device = deviceService.saveDevice(device); - relationService.saveRelation(TenantId.SYS_TENANT_ID, new EntityRelation(gateway.getId(), device.getId(), "Created")); + relationService.saveRelation(tenantId, new EntityRelation(gateway.getId(), device.getId(), "Created")); TbMsgMetaData metaData = new TbMsgMetaData(); CustomerId customerId = gateway.getCustomerId(); From 5a238415bee3326c740352abe26cadb08f78543d Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Thu, 13 Mar 2025 14:52:58 +0200 Subject: [PATCH 074/116] fixed cluster issues --- ...alculatedFieldManagerMessageProcessor.java | 31 ++++++++++++++++--- .../server/actors/tenant/TenantActor.java | 2 +- ...faultTbCalculatedFieldConsumerService.java | 8 ++--- .../server/controller/AbstractWebTest.java | 5 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index b0185fd555..cd1d05d726 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -22,6 +22,7 @@ import org.thingsboard.server.actors.TbActorRef; import org.thingsboard.server.actors.TbCalculatedFieldEntityActorId; import org.thingsboard.server.actors.service.DefaultActorService; import org.thingsboard.server.actors.shared.AbstractContextAwareMsgProcessor; +import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.EntityType; import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.cf.CalculatedFieldLink; @@ -35,6 +36,7 @@ import org.thingsboard.server.common.msg.cf.CalculatedFieldInitMsg; import org.thingsboard.server.common.msg.cf.CalculatedFieldLinkInitMsg; import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; +import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; import org.thingsboard.server.dao.cf.CalculatedFieldService; import org.thingsboard.server.service.cf.CalculatedFieldProcessingService; @@ -178,6 +180,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware EntityId entityId = msg.getEntityId(); EntityId profileId = getProfileId(tenantId, entityId); cfEntityCache.add(tenantId, profileId, entityId); + if (!isMyPartition(entityId, callback)) { + return; + } var entityIdFields = getCalculatedFieldsByEntityId(entityId); var profileIdFields = getCalculatedFieldsByEntityId(profileId); var fieldsCount = entityIdFields.size() + profileIdFields.size(); @@ -193,6 +198,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware private void onEntityUpdated(ComponentLifecycleMsg msg, TbCallback callback) { if (msg.getOldProfileId() != null && msg.getOldProfileId() != msg.getProfileId()) { cfEntityCache.update(tenantId, msg.getOldProfileId(), msg.getProfileId(), msg.getEntityId()); + if (!isMyPartition(msg.getEntityId(), callback)) { + return; + } var oldProfileCfs = getCalculatedFieldsByEntityId(msg.getOldProfileId()); var newProfileCfs = getCalculatedFieldsByEntityId(msg.getProfileId()); var fieldsCount = oldProfileCfs.size() + newProfileCfs.size(); @@ -209,8 +217,10 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware private void onEntityDeleted(ComponentLifecycleMsg msg, TbCallback callback) { cfEntityCache.evict(tenantId, msg.getEntityId()); - log.info("Pushing entity lifecycle msg to specific actor [{}]", msg.getEntityId()); - getOrCreateActor(msg.getEntityId()).tell(new CalculatedFieldEntityDeleteMsg(tenantId, msg.getEntityId(), callback)); + if (isMyPartition(msg.getEntityId(), callback)) { + log.info("Pushing entity lifecycle msg to specific actor [{}]", msg.getEntityId()); + getOrCreateActor(msg.getEntityId()).tell(new CalculatedFieldEntityDeleteMsg(tenantId, msg.getEntityId(), callback)); + } } private void onCfCreated(ComponentLifecycleMsg msg, TbCallback callback) throws CalculatedFieldException { @@ -311,7 +321,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware callback.onSuccess(); } } else { - deleteCfForEntity(entityId, cfId, callback); + if (isMyPartition(entityId, callback)) { + deleteCfForEntity(entityId, cfId, callback); + } } } } @@ -418,7 +430,9 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware callback.onSuccess(); } } else { - initCfForEntity(entityId, cfCtx, forceStateReinit, callback); + if (isMyPartition(entityId, callback)) { + initCfForEntity(entityId, cfCtx, forceStateReinit, callback); + } } } @@ -432,6 +446,15 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware getOrCreateActor(entityId).tell(new EntityInitCalculatedFieldMsg(tenantId, cfCtx, callback, forceStateReinit)); } + private boolean isMyPartition(EntityId entityId, TbCallback callback) { + if (!systemContext.getPartitionService().resolve(ServiceType.TB_RULE_ENGINE, DataConstants.CF_QUEUE_NAME, tenantId, entityId).isMyPartition()) { + log.debug("[{}] Entity belongs to external partition.", entityId); + callback.onSuccess(); + return false; + } + return true; + } + private static boolean isProfileEntity(EntityType entityType) { return EntityType.DEVICE_PROFILE.equals(entityType) || EntityType.ASSET_PROFILE.equals(entityType); } diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index f9eec324fc..c1a0980623 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -112,7 +112,7 @@ public class TenantActor extends RuleChainManagerActor { cantFindTenant = true; } } else { - log.info("Tenant {} is not managed by current service, skipping rule chains init", tenantId); + log.info("Tenant {} is not managed by current service, skipping rule chains and cf actor init", tenantId); } } log.debug("[{}] Tenant actor started.", tenantId); diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java index ad248cc3d4..3232a9b89f 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java @@ -15,15 +15,12 @@ */ package org.thingsboard.server.service.queue; -import com.google.common.util.concurrent.ListeningExecutorService; -import com.google.common.util.concurrent.MoreExecutors; import jakarta.annotation.PostConstruct; import jakarta.annotation.PreDestroy; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; -import org.thingsboard.common.util.ThingsBoardExecutors; import org.thingsboard.server.actors.ActorSystemContext; import org.thingsboard.server.actors.calculatedField.CalculatedFieldLinkedTelemetryMsg; import org.thingsboard.server.actors.calculatedField.CalculatedFieldTelemetryMsg; @@ -35,7 +32,7 @@ import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg; import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.common.msg.queue.TopicPartitionInfo; +import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldLinkedTelemetryMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldTelemetryMsgProto; @@ -60,7 +57,6 @@ import org.thingsboard.server.service.queue.processing.IdMsgPair; import org.thingsboard.server.service.security.auth.jwt.settings.JwtSettingsService; import java.util.List; -import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -220,7 +216,7 @@ public class DefaultTbCalculatedFieldConsumerService extends AbstractConsumerSer protected void handleNotification(UUID id, TbProtoQueueMsg msg, TbCallback callback) { ToCalculatedFieldNotificationMsg toCfNotification = msg.getValue(); if (toCfNotification.hasComponentLifecycleMsg()) { - // from upstream (maybe removed since we don't need to init state for each partition) + handleComponentLifecycleMsg(id, ProtoUtils.fromProto(toCfNotification.getComponentLifecycleMsg())); log.trace("[{}] Forwarding component lifecycle message for processing {}", id, toCfNotification.getComponentLifecycleMsg()); forwardToActorSystem(toCfNotification.getComponentLifecycleMsg(), callback); } else if (toCfNotification.hasLinkedTelemetryMsg()) { diff --git a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java index e90aecb41e..33f2209eca 100644 --- a/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/AbstractWebTest.java @@ -38,6 +38,7 @@ import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; @@ -143,6 +144,7 @@ import org.thingsboard.server.dao.device.ClaimDevicesService; import org.thingsboard.server.dao.tenant.TenantProfileService; import org.thingsboard.server.dao.timeseries.TimeseriesService; import org.thingsboard.server.queue.memory.InMemoryStorage; +import org.thingsboard.server.service.cf.CfRocksDb; import org.thingsboard.server.service.entitiy.tenant.profile.TbTenantProfileService; import org.thingsboard.server.service.security.auth.jwt.RefreshTokenRequest; import org.thingsboard.server.service.security.auth.rest.LoginRequest; @@ -276,6 +278,9 @@ public abstract class AbstractWebTest extends AbstractInMemoryStorageTest { @Autowired protected InMemoryStorage storage; + @MockBean + protected CfRocksDb cfRocksDb; + @Rule public TestRule watcher = new TestWatcher() { protected void starting(Description description) { From 1e0fd6c387734494f45186b83de7303a9037f004 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Thu, 13 Mar 2025 15:34:02 +0200 Subject: [PATCH 075/116] changed log level --- .../CalculatedFieldManagerMessageProcessor.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index cd1d05d726..2d182510e9 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -123,7 +123,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware if (calculatedField != null) { msg.getState().setRequiredArguments(calculatedField.getArgNames()); - log.info("Pushing CF state restore msg to specific actor [{}]", msg.getId().entityId()); + log.debug("Pushing CF state restore msg to specific actor [{}]", msg.getId().entityId()); getOrCreateActor(msg.getId().entityId()).tell(msg); } else { cfStateService.removeState(msg.getId(), msg.getCallback()); @@ -218,7 +218,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware private void onEntityDeleted(ComponentLifecycleMsg msg, TbCallback callback) { cfEntityCache.evict(tenantId, msg.getEntityId()); if (isMyPartition(msg.getEntityId(), callback)) { - log.info("Pushing entity lifecycle msg to specific actor [{}]", msg.getEntityId()); + log.debug("Pushing entity lifecycle msg to specific actor [{}]", msg.getEntityId()); getOrCreateActor(msg.getEntityId()).tell(new CalculatedFieldEntityDeleteMsg(tenantId, msg.getEntityId(), callback)); } } @@ -437,12 +437,12 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware } private void deleteCfForEntity(EntityId entityId, CalculatedFieldId cfId, TbCallback callback) { - log.info("Pushing delete CF msg to specific actor [{}]", entityId); + log.debug("Pushing delete CF msg to specific actor [{}]", entityId); getOrCreateActor(entityId).tell(new CalculatedFieldEntityDeleteMsg(tenantId, cfId, callback)); } private void initCfForEntity(EntityId entityId, CalculatedFieldCtx cfCtx, boolean forceStateReinit, TbCallback callback) { - log.info("Pushing entity init CF msg to specific actor [{}]", entityId); + log.debug("Pushing entity init CF msg to specific actor [{}]", entityId); getOrCreateActor(entityId).tell(new EntityInitCalculatedFieldMsg(tenantId, cfCtx, callback, forceStateReinit)); } From b4fbc6261e589dc8b38c1d998c3d7d76b7d72d0c Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 13 Mar 2025 15:38:36 +0200 Subject: [PATCH 076/116] UI: Fixed default events and add hot keys for mac --- .../layout/dashboard-layout.component.ts | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts index b732b7ff09..510fc1ce63 100644 --- a/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts +++ b/ui-ngx/src/app/modules/home/components/dashboard-page/layout/dashboard-layout.component.ts @@ -174,66 +174,71 @@ export class DashboardLayoutComponent extends PageComponent implements ILayoutCo private initHotKeys(): void { this.hotKeys.push( - new Hotkey('ctrl+c', (event: KeyboardEvent) => { + new Hotkey(['ctrl+c', 'meta+c'], (event: KeyboardEvent) => { if (this.isEdit && !this.isEditingWidget && !this.widgetEditMode) { const widget = this.dashboard.getSelectedWidget(); if (widget) { event.preventDefault(); this.copyWidget(event, widget); } + return false; } - return false; + return true; }, null, this.translate.instant('action.copy')) ); this.hotKeys.push( - new Hotkey('ctrl+r', (event: KeyboardEvent) => { + new Hotkey(['ctrl+r', 'meta+r'], (event: KeyboardEvent) => { if (this.isEdit && !this.isEditingWidget && !this.widgetEditMode) { const widget = this.dashboard.getSelectedWidget(); if (widget) { event.preventDefault(); this.copyWidgetReference(event, widget); } + return false; } - return false; + return true; }, null, this.translate.instant('action.copy-reference')) ); this.hotKeys.push( - new Hotkey('ctrl+v', (event: KeyboardEvent) => { + new Hotkey(['ctrl+v', 'meta+v'], (event: KeyboardEvent) => { if (this.isEdit && !this.isEditingWidget && !this.widgetEditMode) { if (this.itembuffer.hasWidget()) { event.preventDefault(); this.pasteWidget(event); } + return false; } - return false; + return true; }, null, this.translate.instant('action.paste')) ); this.hotKeys.push( - new Hotkey('ctrl+i', (event: KeyboardEvent) => { + new Hotkey(['ctrl+i', 'meta+i'], (event: KeyboardEvent) => { if (this.isEdit && !this.isEditingWidget && !this.widgetEditMode) { if (this.itembuffer.canPasteWidgetReference(this.dashboardCtx.getDashboard(), this.dashboardCtx.state, this.layoutCtx.id, this.layoutCtx.breakpoint)) { event.preventDefault(); this.pasteWidgetReference(event); } + return false; } - return false; + return true; }, null, this.translate.instant('action.paste-reference')) ); this.hotKeys.push( - new Hotkey('ctrl+x', (event: KeyboardEvent) => { + new Hotkey(['ctrl+x', 'meta+x'], (event: KeyboardEvent) => { if (this.isEdit && !this.isEditingWidget && !this.widgetEditMode) { const widget = this.dashboard.getSelectedWidget(); if (widget) { event.preventDefault(); this.layoutCtx.dashboardCtrl.removeWidget(event, this.layoutCtx, widget); } + return false; } - return false; + return true; }, null, this.translate.instant('action.delete')) ); From e900e6ed86955792ac3cb753dece13ee3d29521c Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 13 Mar 2025 15:39:15 +0200 Subject: [PATCH 077/116] Fix license header --- .../thingsboard/server/actors/service/ComponentActorTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/application/src/test/java/org/thingsboard/server/actors/service/ComponentActorTest.java b/application/src/test/java/org/thingsboard/server/actors/service/ComponentActorTest.java index f847ca7db7..49bf3c8670 100644 --- a/application/src/test/java/org/thingsboard/server/actors/service/ComponentActorTest.java +++ b/application/src/test/java/org/thingsboard/server/actors/service/ComponentActorTest.java @@ -1,5 +1,5 @@ /** - * Copyright © 2016-2024 The Thingsboard Authors + * Copyright © 2016-2025 The Thingsboard Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. From 340263f00ba11209491a30d56e47a70b8740bdf4 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Thu, 13 Mar 2025 16:00:55 +0200 Subject: [PATCH 078/116] UI: Refactoring --- ui-ngx/src/app/modules/home/pages/admin/settings-card.scss | 4 ++++ ui-ngx/src/styles.scss | 4 ---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ui-ngx/src/app/modules/home/pages/admin/settings-card.scss b/ui-ngx/src/app/modules/home/pages/admin/settings-card.scss index 50cd35d9da..7c707dee6d 100644 --- a/ui-ngx/src/app/modules/home/pages/admin/settings-card.scss +++ b/ui-ngx/src/app/modules/home/pages/admin/settings-card.scss @@ -19,6 +19,10 @@ .mat-mdc-card.settings-card { margin: 8px; + mat-card-header.mat-mdc-card-header { + align-items: center; + } + .fields-group { padding: 0 16px 8px; margin: 10px 0; diff --git a/ui-ngx/src/styles.scss b/ui-ngx/src/styles.scss index 4369514fff..539a3b1960 100644 --- a/ui-ngx/src/styles.scss +++ b/ui-ngx/src/styles.scss @@ -736,10 +736,6 @@ pre.tb-highlight { } } - mat-card-header.mat-mdc-card-header { - align-items: center; - } - .mat-mdc-footer-row::after, .mat-mdc-header-row::after, .mat-mdc-row::after { content: none; } From 46262e870938cb5f9557cbaf1f705481ed817361 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Thu, 13 Mar 2025 16:37:28 +0200 Subject: [PATCH 079/116] fixed entity relation cleanup method --- .../thingsboard/server/service/entitiy/EntityServiceTest.java | 4 ++++ .../thingsboard/server/dao/relation/BaseRelationService.java | 3 +++ 2 files changed, 7 insertions(+) diff --git a/application/src/test/java/org/thingsboard/server/service/entitiy/EntityServiceTest.java b/application/src/test/java/org/thingsboard/server/service/entitiy/EntityServiceTest.java index 18687cedba..1e7f5384b5 100644 --- a/application/src/test/java/org/thingsboard/server/service/entitiy/EntityServiceTest.java +++ b/application/src/test/java/org/thingsboard/server/service/entitiy/EntityServiceTest.java @@ -282,6 +282,10 @@ public class EntityServiceTest extends AbstractControllerTest { data.forEach(entityData -> Assert.assertNotNull(entityData.getLatest().get(EntityKeyType.ENTITY_FIELD).get("phone"))); countByQueryAndCheck(query, 5); + + // delete user + userService.deleteUser(tenantId, users.get(0)); + countByQueryAndCheck(query, 4); } private void createTestUserRelations(TenantId tenantId, List users) { diff --git a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java index a0e75e062c..87f7e44a1f 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/relation/BaseRelationService.java @@ -236,6 +236,7 @@ public class BaseRelationService implements RelationService { return Futures.transform(future, deletedEvent -> { if (deletedEvent != null) { handleEvictEvent(EntityRelationEvent.from(deletedEvent)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, deletedEvent, ActionType.RELATION_DELETED)); } return deletedEvent != null; }, MoreExecutors.directExecutor()); @@ -267,6 +268,7 @@ public class BaseRelationService implements RelationService { for (EntityRelation relation : inboundRelations) { eventPublisher.publishEvent(EntityRelationEvent.from(relation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED)); } List outboundRelations; @@ -278,6 +280,7 @@ public class BaseRelationService implements RelationService { for (EntityRelation relation : outboundRelations) { eventPublisher.publishEvent(EntityRelationEvent.from(relation)); + eventPublisher.publishEvent(new RelationActionEvent(tenantId, relation, ActionType.RELATION_DELETED)); } } From 2fb1e23c9178ed2a7ed7cc11f9d3c103cb02473a Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 13 Mar 2025 17:04:31 +0200 Subject: [PATCH 080/116] UI: Fix map marker icon transform fon safari browsers. --- .../models/widget/maps/marker-shape.models.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/ui-ngx/src/app/shared/models/widget/maps/marker-shape.models.ts b/ui-ngx/src/app/shared/models/widget/maps/marker-shape.models.ts index 29e04dbaa1..46899ccd11 100644 --- a/ui-ngx/src/app/shared/models/widget/maps/marker-shape.models.ts +++ b/ui-ngx/src/app/shared/models/widget/maps/marker-shape.models.ts @@ -95,7 +95,7 @@ interface MarkerIconContainerDefinition { iconSize: number; iconColor: (color: tinycolor.Instance) => tinycolor.Instance; iconAlpha: (color: tinycolor.Instance) => number; - appendIcon?: (svgElement: SVGElement, iconElement: Element) => void; + appendIcon?: (svgElement: SVGElement, iconElement: Element, iconSize: number) => void; } const emptyIconContainerDefinition: MarkerIconContainerDefinition = { @@ -114,14 +114,16 @@ const defaultTripIconContainerDefinition: MarkerIconContainerDefinition = { iconSize: 24, iconColor: () => tinycolor('#000'), iconAlpha: () => 1, - appendIcon: (svgElement, iconElement) => { + appendIcon: (svgElement, iconElement, iconSize) => { const box = iconElement.bbox(); + const cx = iconSize/2 + box.x; + const cy = iconSize/2 + box.y; let elements = svgElement.getElementsByClassName('icon-mask-exclude'); if (elements.length) { elements = elements[0].getElementsByClassName('marker-icon-container'); if (elements.length) { const iconContainer = new G(elements[0] as SVGGElement); - iconContainer.add(iconElement.clone().fill('#000').translate(-box.cx, -box.cy)); + iconContainer.add(iconElement.clone().fill('#000').translate(-cx, -cy)); } } elements = svgElement.getElementsByClassName('icon-mask-overlay'); @@ -129,7 +131,7 @@ const defaultTripIconContainerDefinition: MarkerIconContainerDefinition = { elements = elements[0].getElementsByClassName('marker-icon-container'); if (elements.length) { const iconContainer = new G(elements[0] as SVGGElement); - iconContainer.add(iconElement.clone().fill('#fff').translate(-box.cx, -box.cy)); + iconContainer.add(iconElement.clone().fill('#fff').translate(-cx, -cy)); } } } @@ -302,14 +304,14 @@ export const createColorMarkerIconElement = (iconRegistry: MatIconRegistry, domS if (svgElement) { if (iconElement) { if (definition.appendIcon) { - definition.appendIcon(svgElement, iconElement); + definition.appendIcon(svgElement, iconElement, iconSize); } else { const elements = svgElement.getElementsByClassName('marker-icon-container'); if (elements.length) { const iconContainer = new G(elements[0] as SVGGElement); iconContainer.add(iconElement); const box = iconElement.bbox(); - iconElement.translate(-box.cx, -box.cy); + iconElement.translate(-(iconSize/2 + box.x), -(iconSize/2 + box.y)); } } } @@ -321,7 +323,7 @@ export const createColorMarkerIconElement = (iconRegistry: MatIconRegistry, domS iconContainer.translate(iconSize/2,iconSize/2); iconContainer.add(iconElement); const box = iconElement.bbox(); - iconElement.translate(-box.cx, -box.cy); + iconElement.translate(-(iconSize/2 + box.x), -(iconSize/2 + box.y)); svg.add(iconContainer); return svg.node; } From b40fa86bac2ed81fca5be45d08711288f4f8392a Mon Sep 17 00:00:00 2001 From: ViacheslavKlimov Date: Thu, 13 Mar 2025 17:35:00 +0200 Subject: [PATCH 081/116] Refactoring and fixes for CF lifecycle events handling --- .../server/actors/app/AppActor.java | 1 - ...alculatedFieldManagerMessageProcessor.java | 2 +- .../server/actors/tenant/TenantActor.java | 31 +++--- ...faultTbCalculatedFieldConsumerService.java | 19 +--- .../queue/DefaultTbClusterService.java | 101 +++++------------- .../DefaultTbRuleEngineConsumerService.java | 3 +- .../server/cluster/TbClusterService.java | 2 - .../server/common/data/EntityType.java | 11 ++ .../cf/CalculatedFieldEntityLifecycleMsg.java | 3 - common/proto/src/main/proto/queue.proto | 8 +- .../discovery/event/PartitionChangeEvent.java | 1 - 11 files changed, 63 insertions(+), 119 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java index 50fa7e2f8d..904547a2b6 100644 --- a/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/app/AppActor.java @@ -116,7 +116,6 @@ public class AppActor extends ContextAwareActor { case CF_INIT_MSG: case CF_LINK_INIT_MSG: case CF_STATE_RESTORE_MSG: - case CF_ENTITY_LIFECYCLE_MSG: //TODO: use priority from the message body. For example, messages about CF lifecycle are important and Device lifecycle are not. // same for the Linked telemetry. onToCalculatedFieldSystemActorMsg((ToCalculatedFieldSystemMsg) msg, true); diff --git a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java index 2d182510e9..fc48e9ad3e 100644 --- a/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java +++ b/application/src/main/java/org/thingsboard/server/actors/calculatedField/CalculatedFieldManagerMessageProcessor.java @@ -196,7 +196,7 @@ public class CalculatedFieldManagerMessageProcessor extends AbstractContextAware } private void onEntityUpdated(ComponentLifecycleMsg msg, TbCallback callback) { - if (msg.getOldProfileId() != null && msg.getOldProfileId() != msg.getProfileId()) { + if (msg.getOldProfileId() != null && !msg.getOldProfileId().equals(msg.getProfileId())) { cfEntityCache.update(tenantId, msg.getOldProfileId(), msg.getProfileId(), msg.getEntityId()); if (!isMyPartition(msg.getEntityId(), callback)) { return; diff --git a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java index c1a0980623..846bde508d 100644 --- a/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java +++ b/application/src/main/java/org/thingsboard/server/actors/tenant/TenantActor.java @@ -49,6 +49,7 @@ import org.thingsboard.server.common.msg.TbMsg; import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg; import org.thingsboard.server.common.msg.aware.DeviceAwareMsg; import org.thingsboard.server.common.msg.aware.RuleChainAwareMsg; +import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.PartitionChangeMsg; import org.thingsboard.server.common.msg.queue.QueueToRuleEngineMsg; @@ -175,7 +176,6 @@ public class TenantActor extends RuleChainManagerActor { case CF_LINK_INIT_MSG: case CF_STATE_RESTORE_MSG: case CF_PARTITIONS_CHANGE_MSG: - case CF_ENTITY_LIFECYCLE_MSG: onToCalculatedFieldSystemActorMsg((ToCalculatedFieldSystemMsg) msg, true); break; case CF_TELEMETRY_MSG: @@ -315,19 +315,26 @@ public class TenantActor extends RuleChainManagerActor { onToDeviceActorMsg(new DeviceDeleteMsg(tenantId, deviceId), true); deletedDevices.add(deviceId); } - if (isRuleEngine && ruleChainsInitialized) { - TbActorRef target = getEntityActorRef(msg.getEntityId()); - if (target != null) { - if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { - RuleChain ruleChain = systemContext.getRuleChainService(). - findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); - if (ruleChain != null && RuleChainType.CORE.equals(ruleChain.getType())) { - visit(ruleChain, target); + if (isRuleEngine) { + if (ruleChainsInitialized) { + TbActorRef target = getEntityActorRef(msg.getEntityId()); + if (target != null) { + if (msg.getEntityId().getEntityType() == EntityType.RULE_CHAIN) { + RuleChain ruleChain = systemContext.getRuleChainService(). + findRuleChainById(tenantId, new RuleChainId(msg.getEntityId().getId())); + if (ruleChain != null && RuleChainType.CORE.equals(ruleChain.getType())) { + visit(ruleChain, target); + } } + target.tellWithHighPriority(msg); + } else { + log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); + } + } + if (cfActor != null) { + if (msg.getEntityId().getEntityType().isOneOf(EntityType.CALCULATED_FIELD, EntityType.DEVICE, EntityType.ASSET)) { + cfActor.tellWithHighPriority(new CalculatedFieldEntityLifecycleMsg(tenantId, msg)); } - target.tellWithHighPriority(msg); - } else { - log.debug("[{}] Invalid component lifecycle msg: {}", tenantId, msg); } } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java index 3232a9b89f..04aab6b39d 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbCalculatedFieldConsumerService.java @@ -28,15 +28,12 @@ import org.thingsboard.server.common.data.DataConstants; import org.thingsboard.server.common.data.id.EntityIdFactory; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.queue.QueueConfig; -import org.thingsboard.server.common.msg.cf.CalculatedFieldEntityLifecycleMsg; import org.thingsboard.server.common.msg.cf.CalculatedFieldPartitionChangeMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; -import org.thingsboard.server.common.util.ProtoUtils; import org.thingsboard.server.dao.tenant.TbTenantProfileCache; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldLinkedTelemetryMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.CalculatedFieldTelemetryMsgProto; -import org.thingsboard.server.gen.transport.TransportProtos.ComponentLifecycleMsgProto; import org.thingsboard.server.gen.transport.TransportProtos.ToCalculatedFieldMsg; import org.thingsboard.server.gen.transport.TransportProtos.ToCalculatedFieldNotificationMsg; import org.thingsboard.server.queue.TbQueueConsumer; @@ -65,8 +62,6 @@ import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; -import static org.thingsboard.server.common.util.ProtoUtils.fromProto; - @Service @TbRuleEngineComponent @Slf4j @@ -164,9 +159,6 @@ public class DefaultTbCalculatedFieldConsumerService extends AbstractConsumerSer forwardToActorSystem(toCfMsg.getTelemetryMsg(), callback); } else if (toCfMsg.hasLinkedTelemetryMsg()) { forwardToActorSystem(toCfMsg.getLinkedTelemetryMsg(), callback); - } else if (toCfMsg.hasComponentLifecycleMsg()) { - log.trace("[{}] Forwarding component lifecycle message for processing {}", id, toCfMsg.getComponentLifecycleMsg()); - forwardToActorSystem(toCfMsg.getComponentLifecycleMsg(), callback); } } catch (Throwable e) { log.warn("[{}] Failed to process message: {}", id, msg, e); @@ -215,11 +207,7 @@ public class DefaultTbCalculatedFieldConsumerService extends AbstractConsumerSer @Override protected void handleNotification(UUID id, TbProtoQueueMsg msg, TbCallback callback) { ToCalculatedFieldNotificationMsg toCfNotification = msg.getValue(); - if (toCfNotification.hasComponentLifecycleMsg()) { - handleComponentLifecycleMsg(id, ProtoUtils.fromProto(toCfNotification.getComponentLifecycleMsg())); - log.trace("[{}] Forwarding component lifecycle message for processing {}", id, toCfNotification.getComponentLifecycleMsg()); - forwardToActorSystem(toCfNotification.getComponentLifecycleMsg(), callback); - } else if (toCfNotification.hasLinkedTelemetryMsg()) { + if (toCfNotification.hasLinkedTelemetryMsg()) { forwardToActorSystem(toCfNotification.getLinkedTelemetryMsg(), callback); } } @@ -237,11 +225,6 @@ public class DefaultTbCalculatedFieldConsumerService extends AbstractConsumerSer actorContext.tell(new CalculatedFieldLinkedTelemetryMsg(tenantId, entityId, linkedMsg, callback)); } - private void forwardToActorSystem(ComponentLifecycleMsgProto proto, TbCallback callback) { - var msg = fromProto(proto); - actorContext.tell(new CalculatedFieldEntityLifecycleMsg(msg.getTenantId(), msg, callback)); - } - private TenantId toTenantId(long tenantIdMSB, long tenantIdLSB) { return TenantId.fromUUID(new UUID(tenantIdMSB, tenantIdLSB)); } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java index c7174469b0..92c48a5fed 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbClusterService.java @@ -94,10 +94,8 @@ import org.thingsboard.server.queue.common.MultipleTbQueueCallbackWrapper; import org.thingsboard.server.queue.common.TbProtoQueueMsg; import org.thingsboard.server.queue.common.TbRuleEngineProducerService; import org.thingsboard.server.queue.discovery.PartitionService; -import org.thingsboard.server.queue.discovery.QueueKey; import org.thingsboard.server.queue.discovery.TopicService; import org.thingsboard.server.queue.provider.TbQueueProducerProvider; -import org.thingsboard.server.service.cf.CalculatedFieldProcessingService; import org.thingsboard.server.service.gateway_device.GatewayNotificationsService; import org.thingsboard.server.service.ota.OtaPackageStateService; import org.thingsboard.server.service.profile.TbAssetProfileCache; @@ -146,10 +144,6 @@ public class DefaultTbClusterService implements TbClusterService { @Lazy private OtaPackageStateService otaPackageStateService; - @Autowired - @Lazy - private CalculatedFieldProcessingService calculatedFieldProcessingService; - private final TopicService topicService; private final TbDeviceProfileCache deviceProfileCache; private final TbAssetProfileCache assetProfileCache; @@ -369,13 +363,6 @@ public class DefaultTbClusterService implements TbClusterService { toRuleEngineMsgs.incrementAndGet(); // TODO: add separate counter when we will have new ServiceType.CALCULATED_FIELDS } - @Override - public void pushNotificationToCalculatedFields(TenantId tenantId, EntityId entityId, ToCalculatedFieldNotificationMsg msg, TbQueueCallback callback) { - TopicPartitionInfo tpi = partitionService.resolve(ServiceType.TB_RULE_ENGINE, DataConstants.CF_QUEUE_NAME, tenantId, entityId); - producerProvider.getCalculatedFieldsNotificationsMsgProducer().send(tpi, new TbProtoQueueMsg<>(UUID.randomUUID(), msg), callback); - toRuleEngineNfs.incrementAndGet(); - } - @Override public void broadcastEntityStateChangeEvent(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state) { log.trace("[{}] Processing {} state change event: {}", tenantId, entityId.getEntityType(), state); @@ -431,7 +418,6 @@ public class DefaultTbClusterService implements TbClusterService { public void onDeviceDeleted(TenantId tenantId, Device device, TbQueueCallback callback) { DeviceId deviceId = device.getId(); gatewayNotificationsService.onDeviceDeleted(device); - handleCalculatedFieldEntityDeleted(tenantId, deviceId); broadcastEntityDeleteToTransport(tenantId, deviceId, device.getName(), callback); sendDeviceStateServiceEvent(tenantId, deviceId, false, false, true); broadcastEntityStateChangeEvent(tenantId, deviceId, ComponentLifecycleEvent.DELETED); @@ -440,7 +426,6 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void onAssetDeleted(TenantId tenantId, Asset asset, TbQueueCallback callback) { AssetId assetId = asset.getId(); - handleCalculatedFieldEntityDeleted(tenantId, assetId); broadcastEntityStateChangeEvent(tenantId, assetId, ComponentLifecycleEvent.DELETED); } @@ -604,6 +589,7 @@ public class DefaultTbClusterService implements TbClusterService { || (entityType.equals(EntityType.DEVICE) && msg.getEvent() == ComponentLifecycleEvent.UPDATED) || entityType.equals(EntityType.ENTITY_VIEW) || entityType.equals(EntityType.NOTIFICATION_RULE) + || entityType.equals(EntityType.CALCULATED_FIELD) ) { TbQueueProducer> toCoreNfProducer = producerProvider.getTbCoreNotificationsMsgProducer(); Set tbCoreServices = partitionService.getAllServiceIds(ServiceType.TB_CORE); @@ -658,38 +644,28 @@ public class DefaultTbClusterService implements TbClusterService { public void onDeviceUpdated(Device entity, Device old) { var created = old == null; broadcastEntityChangeToTransport(entity.getTenantId(), entity.getId(), entity, null); - if (old != null) { + + var msg = ComponentLifecycleMsg.builder() + .tenantId(entity.getTenantId()) + .entityId(entity.getId()) + .profileId(entity.getDeviceProfileId()) + .name(entity.getName()); + if (created) { + msg.event(ComponentLifecycleEvent.CREATED); + } else { boolean deviceNameChanged = !entity.getName().equals(old.getName()); if (deviceNameChanged) { gatewayNotificationsService.onDeviceUpdated(entity, old); } boolean deviceProfileChanged = !entity.getDeviceProfileId().equals(old.getDeviceProfileId()); - if (deviceProfileChanged) { - ComponentLifecycleMsg msg = ComponentLifecycleMsg.builder() - .tenantId(entity.getTenantId()) - .entityId(entity.getId()) - .event(ComponentLifecycleEvent.UPDATED) - .oldProfileId(old.getDeviceProfileId()) - .profileId(entity.getDeviceProfileId()) - .oldName(old.getName()) - .name(entity.getName()) - .build(); - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(toProto(msg)).build(), TbQueueCallback.EMPTY); - } if (deviceNameChanged || deviceProfileChanged) { pushMsgToCore(new DeviceNameOrTypeUpdateMsg(entity.getTenantId(), entity.getId(), entity.getName(), entity.getType()), null); } - } else { - ComponentLifecycleMsg msg = ComponentLifecycleMsg.builder() - .tenantId(entity.getTenantId()) - .entityId(entity.getId()) - .event(ComponentLifecycleEvent.CREATED) - .profileId(entity.getDeviceProfileId()) - .name(entity.getName()) - .build(); - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(toProto(msg)).build(), TbQueueCallback.EMPTY); + msg.event(ComponentLifecycleEvent.UPDATED) + .oldProfileId(old.getDeviceProfileId()) + .oldName(old.getName()); } - broadcastEntityStateChangeEvent(entity.getTenantId(), entity.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); + broadcast(msg.build()); sendDeviceStateServiceEvent(entity.getTenantId(), entity.getId(), created, !created, false); otaPackageStateService.update(entity, old); } @@ -697,48 +673,29 @@ public class DefaultTbClusterService implements TbClusterService { @Override public void onAssetUpdated(Asset entity, Asset old) { var created = old == null; - if (old != null) { - boolean assetTypeChanged = !entity.getAssetProfileId().equals(old.getAssetProfileId()); - if (assetTypeChanged) { - ComponentLifecycleMsg msg = ComponentLifecycleMsg.builder() - .tenantId(entity.getTenantId()) - .entityId(entity.getId()) - .event(ComponentLifecycleEvent.UPDATED) - .oldProfileId(old.getAssetProfileId()) - .profileId(entity.getAssetProfileId()) - .oldName(old.getName()) - .name(entity.getName()) - .build(); - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(toProto(msg)).build(), TbQueueCallback.EMPTY); - } + var msg = ComponentLifecycleMsg.builder() + .tenantId(entity.getTenantId()) + .entityId(entity.getId()) + .profileId(entity.getAssetProfileId()) + .name(entity.getName()); + if (created) { + msg.event(ComponentLifecycleEvent.CREATED); } else { - ComponentLifecycleMsg msg = ComponentLifecycleMsg.builder() - .tenantId(entity.getTenantId()) - .entityId(entity.getId()) - .event(ComponentLifecycleEvent.CREATED) - .profileId(entity.getAssetProfileId()) - .name(entity.getName()) - .build(); - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(toProto(msg)).build(), TbQueueCallback.EMPTY); + msg.event(ComponentLifecycleEvent.UPDATED) + .oldProfileId(old.getAssetProfileId()) + .oldName(old.getName()); } - broadcastEntityStateChangeEvent(entity.getTenantId(), entity.getId(), created ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); + broadcast(msg.build()); } @Override public void onCalculatedFieldUpdated(CalculatedField calculatedField, CalculatedField oldCalculatedField, TbQueueCallback callback) { - var msg = toProto(new ComponentLifecycleMsg(calculatedField.getTenantId(), calculatedField.getId(), oldCalculatedField == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED)); - onCalculatedFieldLifecycleMsg(msg, callback); + broadcastEntityStateChangeEvent(calculatedField.getTenantId(), calculatedField.getId(), oldCalculatedField == null ? ComponentLifecycleEvent.CREATED : ComponentLifecycleEvent.UPDATED); } @Override public void onCalculatedFieldDeleted(CalculatedField calculatedField, TbQueueCallback callback) { - var msg = toProto(new ComponentLifecycleMsg(calculatedField.getTenantId(), calculatedField.getId(), ComponentLifecycleEvent.DELETED)); - onCalculatedFieldLifecycleMsg(msg, callback); - } - - private void onCalculatedFieldLifecycleMsg(ComponentLifecycleMsgProto msg, TbQueueCallback callback) { - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(msg).build(), callback); - broadcastToCore(ToCoreNotificationMsg.newBuilder().setComponentLifecycle(msg).build()); + broadcastEntityStateChangeEvent(calculatedField.getTenantId(), calculatedField.getId(), ComponentLifecycleEvent.DELETED); } @Override @@ -868,8 +825,4 @@ public class DefaultTbClusterService implements TbClusterService { } } - private void handleCalculatedFieldEntityDeleted(TenantId tenantId, EntityId entityId) { - ComponentLifecycleMsg msg = new ComponentLifecycleMsg(tenantId, entityId, ComponentLifecycleEvent.DELETED); - broadcastToCalculatedFields(ToCalculatedFieldNotificationMsg.newBuilder().setComponentLifecycleMsg(toProto(msg)).build(), TbQueueCallback.EMPTY); - } } diff --git a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java index d522f11f7b..9cc743e510 100644 --- a/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java +++ b/application/src/main/java/org/thingsboard/server/service/queue/DefaultTbRuleEngineConsumerService.java @@ -29,7 +29,6 @@ import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.data.plugin.ComponentLifecycleEvent; import org.thingsboard.server.common.data.queue.Queue; import org.thingsboard.server.common.data.rpc.RpcError; -import org.thingsboard.server.common.data.util.CollectionsUtil; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; import org.thingsboard.server.common.msg.queue.ServiceType; import org.thingsboard.server.common.msg.queue.TbCallback; @@ -234,7 +233,7 @@ public class DefaultTbRuleEngineConsumerService extends AbstractConsumerService< if (event.getEvent() == ComponentLifecycleEvent.DELETED) { List toRemove = consumers.keySet().stream() .filter(queueKey -> queueKey.getTenantId().equals(event.getTenantId())) - .collect(Collectors.toList()); + .toList(); toRemove.forEach(queueKey -> { removeConsumer(queueKey).ifPresent(consumer -> consumer.delete(false)); }); diff --git a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java index 2a2d04e0fd..aed6eb4cf5 100644 --- a/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java +++ b/common/cluster-api/src/main/java/org/thingsboard/server/cluster/TbClusterService.java @@ -85,8 +85,6 @@ public interface TbClusterService extends TbQueueClusterService { void pushMsgToCalculatedFields(TopicPartitionInfo tpi, UUID msgId, ToCalculatedFieldMsg msg, TbQueueCallback callback); - void pushNotificationToCalculatedFields(TenantId tenantId, EntityId entityId, TransportProtos.ToCalculatedFieldNotificationMsg msg, TbQueueCallback callback); - void broadcastEntityStateChangeEvent(TenantId tenantId, EntityId entityId, ComponentLifecycleEvent state); void onDeviceProfileChange(DeviceProfile deviceProfile, DeviceProfile oldDeviceProfile, TbQueueCallback callback); diff --git a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java index 4ea66be1b4..1c56aa25dd 100644 --- a/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java +++ b/common/data/src/main/java/org/thingsboard/server/common/data/EntityType.java @@ -86,4 +86,15 @@ public enum EntityType { this.tableName = tableName; } + public boolean isOneOf(EntityType... types) { + if (types == null) { + return false; + } + for (EntityType type : types) { + if (this == type) { + return true; + } + } + return false; + } } diff --git a/common/message/src/main/java/org/thingsboard/server/common/msg/cf/CalculatedFieldEntityLifecycleMsg.java b/common/message/src/main/java/org/thingsboard/server/common/msg/cf/CalculatedFieldEntityLifecycleMsg.java index 099240f54d..1eb8f425ab 100644 --- a/common/message/src/main/java/org/thingsboard/server/common/msg/cf/CalculatedFieldEntityLifecycleMsg.java +++ b/common/message/src/main/java/org/thingsboard/server/common/msg/cf/CalculatedFieldEntityLifecycleMsg.java @@ -16,19 +16,16 @@ package org.thingsboard.server.common.msg.cf; import lombok.Data; -import org.thingsboard.server.common.data.cf.CalculatedField; import org.thingsboard.server.common.data.id.TenantId; import org.thingsboard.server.common.msg.MsgType; import org.thingsboard.server.common.msg.ToCalculatedFieldSystemMsg; import org.thingsboard.server.common.msg.plugin.ComponentLifecycleMsg; -import org.thingsboard.server.common.msg.queue.TbCallback; @Data public class CalculatedFieldEntityLifecycleMsg implements ToCalculatedFieldSystemMsg { private final TenantId tenantId; private final ComponentLifecycleMsg data; - private final TbCallback callback; @Override public MsgType getMsgType() { diff --git a/common/proto/src/main/proto/queue.proto b/common/proto/src/main/proto/queue.proto index 6ecdf13981..1b2edcc96d 100644 --- a/common/proto/src/main/proto/queue.proto +++ b/common/proto/src/main/proto/queue.proto @@ -1674,14 +1674,12 @@ message ToEdgeEventNotificationMsg { } message ToCalculatedFieldMsg { - ComponentLifecycleMsgProto componentLifecycleMsg = 1; - CalculatedFieldTelemetryMsgProto telemetryMsg = 2; - CalculatedFieldLinkedTelemetryMsgProto linkedTelemetryMsg = 3; + CalculatedFieldTelemetryMsgProto telemetryMsg = 1; + CalculatedFieldLinkedTelemetryMsgProto linkedTelemetryMsg = 2; } message ToCalculatedFieldNotificationMsg { - ComponentLifecycleMsgProto componentLifecycleMsg = 1; - CalculatedFieldLinkedTelemetryMsgProto linkedTelemetryMsg = 2; + CalculatedFieldLinkedTelemetryMsgProto linkedTelemetryMsg = 1; } /* Messages that are handled by ThingsBoard RuleEngine Service */ diff --git a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java index f165f60be7..32537edba5 100644 --- a/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java +++ b/common/queue/src/main/java/org/thingsboard/server/queue/discovery/event/PartitionChangeEvent.java @@ -24,7 +24,6 @@ import org.thingsboard.server.queue.discovery.QueueKey; import java.io.Serial; import java.util.Collection; -import java.util.Collections; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; From a8ae13faea3f3552c9b4948be4fa113685c81dac Mon Sep 17 00:00:00 2001 From: Igor Kulikov Date: Thu, 13 Mar 2025 18:07:41 +0200 Subject: [PATCH 082/116] UI: Map widget - fix map layers load event. --- ui-ngx/package.json | 2 +- .../widget/lib/maps/leaflet/leaflet-tb.ts | 3 +++ .../home/components/widget/lib/maps/map-layer.ts | 14 ++++++++++++++ ui-ngx/yarn.lock | 8 ++++---- 4 files changed, 22 insertions(+), 5 deletions(-) diff --git a/ui-ngx/package.json b/ui-ngx/package.json index 3323d15b56..1a32c7d41c 100644 --- a/ui-ngx/package.json +++ b/ui-ngx/package.json @@ -61,7 +61,7 @@ "leaflet": "1.9.4", "leaflet-polylinedecorator": "1.6.0", "leaflet-providers": "2.0.0", - "leaflet.gridlayer.googlemutant": "0.14.1", + "leaflet.gridlayer.googlemutant": "0.15.0", "leaflet.markercluster": "1.5.3", "libphonenumber-js": "^1.11.15", "maplibre-gl": "^5.2.0", diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts index 95b8932db0..79e2f11ce6 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/leaflet/leaflet-tb.ts @@ -772,6 +772,9 @@ class MapLibreGLLayer extends L.Layer implements TB.MapLibreGL.MapLibreGLLayer { attributionControl: false }); this._glMap = new MapLibreGLMap(options); + this._glMap.once('load', () => { + this.fire('load'); + }); this._glMap.setMaxBounds(null); this._transformGL(this._glMap); this._actualCanvas = this._glMap._canvas; diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts index b40abd1d66..b3a41ec2f3 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/maps/map-layer.ts @@ -116,8 +116,22 @@ export abstract class TbMapLayer { map((referenceLayer) => { if (referenceLayer) { const layer = L.featureGroup(); + let baseLayerLoaded = false; + let referenceLayerLoaded = false; baseLayer.addTo(layer); referenceLayer.addTo(layer); + baseLayer.once('load', () => { + baseLayerLoaded = true; + if (referenceLayerLoaded) { + layer.fire('load'); + } + }); + referenceLayer.once('load', () => { + referenceLayerLoaded = true; + if (baseLayerLoaded) { + layer.fire('load'); + } + }); return { layer, attribution: !!baseLayer.getAttribution() || !!referenceLayer.getAttribution() diff --git a/ui-ngx/yarn.lock b/ui-ngx/yarn.lock index b3cc13904a..04e0c4f77a 100644 --- a/ui-ngx/yarn.lock +++ b/ui-ngx/yarn.lock @@ -6667,10 +6667,10 @@ leaflet-rotatedmarker@^0.2.0: resolved "https://registry.yarnpkg.com/leaflet-rotatedmarker/-/leaflet-rotatedmarker-0.2.0.tgz#4467f49f98d1bfd56959bd9c6705203dd2601277" integrity sha512-yc97gxLXwbZa+Gk9VCcqI0CkvIBC9oNTTjFsHqq4EQvANrvaboib4UdeQLyTnEqDpaXHCqzwwVIDHtvz2mUiDg== -leaflet.gridlayer.googlemutant@0.14.1: - version "0.14.1" - resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.14.1.tgz#c282209aa1a39eb2f87d8aaa4e9894181c9e20a0" - integrity sha512-/OYxEjmgxO1U1KOhTzg+m8c0b95J0943LU8DXQmdJu/x2f+1Ur78rvEPO2QCS0cmwZ3m6FvE5I3zXnBzJNWRCA== +leaflet.gridlayer.googlemutant@0.15.0: + version "0.15.0" + resolved "https://registry.yarnpkg.com/leaflet.gridlayer.googlemutant/-/leaflet.gridlayer.googlemutant-0.15.0.tgz#7a32d949578695b8aa8fa5fd11b40bd7a6ce6c23" + integrity sha512-kA5jCOBhCPigyue6YpZMhXMVYA1hM2pDIaJ6u0wSSiSZ2TQ4kZfKuhwkIexcadJfs0BP4FyhZIDZC7hmTlvjOA== leaflet.markercluster@1.5.3: version "1.5.3" From 58a5b9f274473efd1b228ef9f6dabeb4289f0976 Mon Sep 17 00:00:00 2001 From: Vladyslav Prykhodko Date: Thu, 13 Mar 2025 20:41:30 +0200 Subject: [PATCH 083/116] UI: Fixed widget-container.component duplicate import --- .../home/components/widget/widget-container.component.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts index 72252ada2c..430cce40b1 100644 --- a/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts +++ b/ui-ngx/src/app/modules/home/components/widget/widget-container.component.ts @@ -44,11 +44,10 @@ import { GridsterItemComponent } from 'angular-gridster2'; import { UtilsService } from '@core/services/utils.service'; import { from } from 'rxjs'; import { DashboardUtilsService } from '@core/services/dashboard-utils.service'; -import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; -import ITooltipsterGeoHelper = JQueryTooltipster.ITooltipsterGeoHelper; import { TbContextMenuEvent } from '@shared/models/jquery-event.models'; import { WidgetHeaderActionButtonType } from '@shared/models/widget.models'; import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance; +import ITooltipsterGeoHelper = JQueryTooltipster.ITooltipsterGeoHelper; export enum WidgetComponentActionType { MOUSE_DOWN, From 2833b69145a9b13cd50431446c0b5ee767ee122f Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 14 Mar 2025 09:15:36 +0200 Subject: [PATCH 084/116] UI: Improvent for key event for rule chain page for Mac --- .../home/pages/rulechain/rulechain-page.component.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) 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 d927f64fdd..2ac9b806e6 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 @@ -369,7 +369,7 @@ export class RuleChainPageComponent extends PageComponent private initHotKeys(): void { if (!this.hotKeys.length) { this.hotKeys.push( - new Hotkey('ctrl+a', (event: KeyboardEvent) => { + new Hotkey(['ctrl+a', 'meta+a'], (event: KeyboardEvent) => { if (this.enableHotKeys) { event.preventDefault(); this.ruleChainCanvas.modelService.selectAll(); @@ -380,7 +380,7 @@ export class RuleChainPageComponent extends PageComponent this.translate.instant('rulenode.select-all-objects')) ); this.hotKeys.push( - new Hotkey('ctrl+c', (event: KeyboardEvent) => { + new Hotkey(['ctrl+c', 'meta+c'], (event: KeyboardEvent) => { if (this.enableHotKeys) { event.preventDefault(); this.copyRuleNodes(); @@ -391,7 +391,7 @@ export class RuleChainPageComponent extends PageComponent this.translate.instant('rulenode.copy-selected')) ); this.hotKeys.push( - new Hotkey('ctrl+v', (event: KeyboardEvent) => { + new Hotkey(['ctrl+v', 'meta+v'], (event: KeyboardEvent) => { if (this.enableHotKeys) { event.preventDefault(); if (this.itembuffer.hasRuleNodes()) { @@ -416,7 +416,7 @@ export class RuleChainPageComponent extends PageComponent this.translate.instant('rulenode.deselect-all-objects')) ); this.hotKeys.push( - new Hotkey('ctrl+s', (event: KeyboardEvent) => { + new Hotkey(['ctrl+s', 'meta+s'], (event: KeyboardEvent) => { if (this.enableHotKeys) { event.preventDefault(); this.saveRuleChain(); @@ -427,7 +427,7 @@ export class RuleChainPageComponent extends PageComponent this.translate.instant('action.apply')) ); this.hotKeys.push( - new Hotkey('ctrl+z', (event: KeyboardEvent) => { + new Hotkey(['ctrl+z', 'meta+z'], (event: KeyboardEvent) => { if (this.enableHotKeys) { event.preventDefault(); this.revertRuleChain(); @@ -449,7 +449,7 @@ export class RuleChainPageComponent extends PageComponent this.translate.instant('rulenode.delete-selected-objects')) ); this.hotKeys.push( - new Hotkey('ctrl+r', (event: KeyboardEvent) => { + new Hotkey(['ctrl+r', 'meta+r'], (event: KeyboardEvent) => { if (this.enableHotKeys && this.canCreateNestedRuleChain()) { event.preventDefault(); this.createNestedRuleChain(); From 78fc8445a7a41ee19d322386eba7c5678a839917 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:32:38 +0200 Subject: [PATCH 085/116] UI: Refactoring calculate fields models refactoring --- .../calculated-fields-table-config.ts | 15 +++++++------- .../calculated-field-dialog.component.ts | 16 ++++++++++++++- ...ated-field-script-test-dialog.component.ts | 10 +++++++++- .../shared/models/calculated-field.models.ts | 20 +------------------ 4 files changed, 32 insertions(+), 29 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 5689f176e9..5e7d532623 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -39,28 +39,27 @@ import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { ArgumentType, CalculatedField, - CalculatedFieldEventArguments, CalculatedFieldDebugDialogData, - CalculatedFieldDialogData, - CalculatedFieldTestScriptDialogData, + CalculatedFieldEventArguments, + CalculatedFieldType, + CalculatedFieldTypeTranslations, getCalculatedFieldArgumentsEditorCompleter, getCalculatedFieldArgumentsHighlights, - CalculatedFieldTypeTranslations, - CalculatedFieldType, } from '@shared/models/calculated-field.models'; import { CalculatedFieldDebugDialogComponent, CalculatedFieldDialogComponent, - CalculatedFieldScriptTestDialogComponent + CalculatedFieldDialogData, + CalculatedFieldScriptTestDialogComponent, + CalculatedFieldTestScriptDialogData } from './components/public-api'; import { ImportExportService } from '@shared/import-export/import-export.service'; import { isObject } from '@core/utils'; import { EntityDebugSettingsService } from '@home/components/entity/debug/entity-debug-settings.service'; import { DatePipe } from '@angular/common'; -export class CalculatedFieldsTableConfig extends EntityTableConfig { +export class CalculatedFieldsTableConfig extends EntityTableConfig { - // TODO: [Calculated Fields] remove hardcode when BE variable implemented readonly calculatedFieldsDebugPerTenantLimitsConfiguration = getCurrentAuthState(this.store)['calculatedFieldsDebugPerTenantLimitsConfiguration'] || '1:1'; readonly maxDebugModeDuration = getCurrentAuthState(this.store).maxDebugModeDurationMinutes * MINUTE; diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts index 0c3e7464cd..631a55f0f6 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/dialog/calculated-field-dialog.component.ts @@ -25,7 +25,7 @@ import { CalculatedField, CalculatedFieldConfiguration, calculatedFieldDefaultScript, - CalculatedFieldDialogData, + CalculatedFieldTestScriptFn, CalculatedFieldType, CalculatedFieldTypeTranslations, getCalculatedFieldArgumentsEditorCompleter, @@ -41,6 +41,20 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; import { ScriptLanguage } from '@shared/models/rule-node.models'; import { CalculatedFieldsService } from '@core/http/calculated-fields.service'; import { Observable } from 'rxjs'; +import { EntityId } from '@shared/models/id/entity-id'; +import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; + +export interface CalculatedFieldDialogData { + value?: CalculatedField; + buttonTitle: string; + entityId: EntityId; + debugLimitsConfiguration: string; + tenantId: string; + entityName?: string; + additionalDebugActionConfig: AdditionalDebugActionConfig<(calculatedField: CalculatedField) => void>; + getTestScriptDialogFn: CalculatedFieldTestScriptFn; + isDirty?: boolean; +} @Component({ selector: 'tb-calculated-field-dialog', diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts index 78c3b17bcb..fbc389939f 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/test-dialog/calculated-field-script-test-dialog.component.ts @@ -41,9 +41,17 @@ import { filter } from 'rxjs/operators'; import { ArgumentType, CalculatedFieldEventArguments, - CalculatedFieldTestScriptDialogData, + CalculatedFieldTestScriptInputParams, TestArgumentTypeMap } from '@shared/models/calculated-field.models'; +import { TbEditorCompleter } from '@shared/models/ace/completion.models'; +import { AceHighlightRules } from '@shared/models/ace/ace.models'; + +export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams { + argumentsEditorCompleter: TbEditorCompleter; + argumentsHighlightRules: AceHighlightRules; + openCalculatedFieldEdit?: boolean; +} @Component({ selector: 'tb-calculated-field-script-test-dialog', diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index c7b37e46f5..8afd280f3a 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -149,18 +149,6 @@ export interface CalculatedFieldArgumentValue extends CalculatedFieldArgument { export type CalculatedFieldTestScriptFn = (calculatedField: CalculatedField, argumentsObj?: Record, closeAllOnSave?: boolean) => Observable; -export interface CalculatedFieldDialogData { - value?: CalculatedField; - buttonTitle: string; - entityId: EntityId; - debugLimitsConfiguration: string; - tenantId: string; - entityName?: string; - additionalDebugActionConfig: AdditionalDebugActionConfig<(calculatedField: CalculatedField) => void>; - getTestScriptDialogFn: CalculatedFieldTestScriptFn; - isDirty?: boolean; -} - export interface CalculatedFieldDebugDialogData { tenantId: string; value: CalculatedField; @@ -172,12 +160,6 @@ export interface CalculatedFieldTestScriptInputParams { expression: string; } -export interface CalculatedFieldTestScriptDialogData extends CalculatedFieldTestScriptInputParams { - argumentsEditorCompleter: TbEditorCompleter; - argumentsHighlightRules: AceHighlightRules; - openCalculatedFieldEdit?: boolean; -} - export interface ArgumentEntityTypeParams { title: string; entityType: EntityType @@ -560,7 +542,7 @@ const calculatedFieldSingleArgumentValueHighlightRules: AceHighlightRules = { } const calculatedFieldRollingArgumentValueFunctionsHighlightRules: Array = - ['max', 'min', 'avg', 'mean', 'std', 'median', 'count', 'last', 'first', 'sum', 'merge', 'mergeAll'].map(funcName => ({ + Object.keys(CalculatedFieldRollingValueArgumentFunctionsAutocomplete).map(funcName => ({ token: 'tb.calculated-field-func', regex: `\\b${funcName}\\b`, next: 'no_regex' From faff769cda3d455de24269a85f9583cdbc04d57f Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:34:13 +0200 Subject: [PATCH 086/116] UI: Refactoring calculate fields models refactoring --- ui-ngx/src/app/shared/models/calculated-field.models.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index 8afd280f3a..c124e39a32 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -33,7 +33,6 @@ import { dotOperatorHighlightRule, endGroupHighlightRule } from '@shared/models/ace/ace.models'; -import { AdditionalDebugActionConfig } from '@home/components/entity/debug/entity-debug-settings.model'; export interface CalculatedField extends Omit, 'label'>, HasVersion, HasEntityDebugSettings, HasTenantId, ExportableEntity { configuration: CalculatedFieldConfiguration; From babda72b1edcc0ea790bb3283dfaf3fc59ad9e45 Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Fri, 14 Mar 2025 11:49:13 +0200 Subject: [PATCH 087/116] Fixed date time period start/end values check --- .../time/datetime-period.component.ts | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/ui-ngx/src/app/shared/components/time/datetime-period.component.ts b/ui-ngx/src/app/shared/components/time/datetime-period.component.ts index 251f9e03b9..99d3fdc661 100644 --- a/ui-ngx/src/app/shared/components/time/datetime-period.component.ts +++ b/ui-ngx/src/app/shared/components/time/datetime-period.component.ts @@ -160,22 +160,26 @@ export class DatetimePeriodComponent implements ControlValueAccessor { private onStartDateChange(startDate: Date) { if (startDate) { - if (startDate.getTime() > this.maxStartTs) { - this.dateTimePeriodFormGroup.get('startDate').patchValue(new Date(this.maxStartTs), { emitEvent: false }); + let startDateTs = startDate.getTime(); + if (startDateTs > this.maxStartTs) { + startDateTs = this.maxStartTs; + this.dateTimePeriodFormGroup.get('startDate').patchValue(new Date(startDateTs), { emitEvent: false }); } - if (startDate.getTime() > this.maxStartDateTs) { - this.dateTimePeriodFormGroup.get('endDate').patchValue(new Date(startDate.getTime() + this.timeShiftMs), { emitEvent: false }); + if (startDateTs > this.maxStartDateTs) { + this.dateTimePeriodFormGroup.get('endDate').patchValue(new Date(startDateTs + this.timeShiftMs), { emitEvent: false }); } } } private onEndDateChange(endDate: Date) { if (endDate) { - if (endDate.getTime() > this.maxEndTs) { - this.dateTimePeriodFormGroup.get('endDate').patchValue(new Date(this.maxEndTs), { emitEvent: false }); + let endDateTs = endDate.getTime(); + if (endDateTs > this.maxEndTs) { + endDateTs = this.maxEndTs; + this.dateTimePeriodFormGroup.get('endDate').patchValue(new Date(endDateTs), { emitEvent: false }); } - if (endDate.getTime() < this.minEndDateTs) { - this.dateTimePeriodFormGroup.get('startDate').patchValue(new Date(endDate.getTime() - this.timeShiftMs), { emitEvent: false }); + if (endDateTs < this.minEndDateTs) { + this.dateTimePeriodFormGroup.get('startDate').patchValue(new Date(endDateTs - this.timeShiftMs), { emitEvent: false }); } } } From 2fec80eef2543db18c6649a25066c5447aef4864 Mon Sep 17 00:00:00 2001 From: Vladyslav_Prykhodko Date: Fri, 14 Mar 2025 11:49:15 +0200 Subject: [PATCH 088/116] UI: Refactoring calculate fields models refactoring --- .../calculated-fields-table-config.ts | 3 +-- .../calculated-field-debug-dialog.component.ts | 12 +++++++++++- .../src/app/shared/models/calculated-field.models.ts | 6 ------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts index 5e7d532623..2c0418bd4f 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-fields-table-config.ts @@ -39,7 +39,6 @@ import { catchError, filter, switchMap, tap } from 'rxjs/operators'; import { ArgumentType, CalculatedField, - CalculatedFieldDebugDialogData, CalculatedFieldEventArguments, CalculatedFieldType, CalculatedFieldTypeTranslations, @@ -47,7 +46,7 @@ import { getCalculatedFieldArgumentsHighlights, } from '@shared/models/calculated-field.models'; import { - CalculatedFieldDebugDialogComponent, + CalculatedFieldDebugDialogComponent, CalculatedFieldDebugDialogData, CalculatedFieldDialogComponent, CalculatedFieldDialogData, CalculatedFieldScriptTestDialogComponent, diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts index 8618a11990..2b987e124a 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/debug-dialog/calculated-field-debug-dialog.component.ts @@ -22,7 +22,17 @@ import { Router } from '@angular/router'; import { DialogComponent } from '@shared/components/dialog.component'; import { CalculatedFieldEventBody, DebugEventType, EventType } from '@shared/models/event.models'; import { EventTableComponent } from '@home/components/event/event-table.component'; -import { CalculatedFieldDebugDialogData, CalculatedFieldType } from '@shared/models/calculated-field.models'; +import { + CalculatedField, + CalculatedFieldTestScriptFn, + CalculatedFieldType +} from '@shared/models/calculated-field.models'; + +export interface CalculatedFieldDebugDialogData { + tenantId: string; + value: CalculatedField; + getTestScriptDialogFn: CalculatedFieldTestScriptFn; +} @Component({ selector: 'tb-calculated-field-debug-dialog', diff --git a/ui-ngx/src/app/shared/models/calculated-field.models.ts b/ui-ngx/src/app/shared/models/calculated-field.models.ts index c124e39a32..9dface6a67 100644 --- a/ui-ngx/src/app/shared/models/calculated-field.models.ts +++ b/ui-ngx/src/app/shared/models/calculated-field.models.ts @@ -148,12 +148,6 @@ export interface CalculatedFieldArgumentValue extends CalculatedFieldArgument { export type CalculatedFieldTestScriptFn = (calculatedField: CalculatedField, argumentsObj?: Record, closeAllOnSave?: boolean) => Observable; -export interface CalculatedFieldDebugDialogData { - tenantId: string; - value: CalculatedField; - getTestScriptDialogFn: CalculatedFieldTestScriptFn; -} - export interface CalculatedFieldTestScriptInputParams { arguments: CalculatedFieldEventArguments; expression: string; From 08556ee697b2019f2171b032c3da88b5a19ef8d0 Mon Sep 17 00:00:00 2001 From: Artem Dzhereleiko Date: Fri, 14 Mar 2025 12:03:15 +0200 Subject: [PATCH 089/116] UI: Refactoring tbel utils autocompletes and highlights --- .../shared/models/ace/tbel-utils.models.ts | 72 ++----------------- 1 file changed, 6 insertions(+), 66 deletions(-) diff --git a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts index f0a04b4762..f29ae083be 100644 --- a/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts +++ b/ui-ngx/src/app/shared/models/ace/tbel-utils.models.ts @@ -15,9 +15,9 @@ /// import { AceHighlightRule } from '@shared/models/ace/ace.models'; -import { TbEditorCompleter } from '@shared/models/ace/completion.models'; +import { TbEditorCompleter, TbEditorCompletions } from '@shared/models/ace/completion.models'; -export const tbelUtilsAutocompletes = new TbEditorCompleter({ +const tbelEditorCompletions:TbEditorCompletions = { btoa: { meta: 'function', description: 'Encodes a string to Base64.', @@ -1245,71 +1245,11 @@ export const tbelUtilsAutocompletes = new TbEditorCompleter({ type: 'boolean' } }, -}); +} -const tbelUtilsFuncNames = [ - "btoa", - "atob", - "bytesToString", - "decodeToString", - "decodeToJson", - "stringToBytes", - "parseInt", - "parseLong", - "parseFloat", - "parseHexIntLongToFloat", - "parseDouble", - "parseLittleEndianHexToInt", - "parseBigEndianHexToInt", - "parseHexToInt", - "parseBytesToInt", - "parseLittleEndianHexToLong", - "parseBigEndianHexToLong", - "parseHexToLong", - "parseBytesToLong", - "parseLittleEndianHexToFloat", - "parseBigEndianHexToFloat", - "parseHexToFloat", - "parseBytesToFloat", - "parseBytesIntToFloat", - "parseLittleEndianHexToDouble", - "parseBigEndianHexToDouble", - "parseHexToDouble", - "parseBytesToDouble", - "parseBytesLongToDouble", - "toFixed", - "toInt", - "hexToBytes", - "hexToBytesArray", - "intToHex", - "longToHex", - "intLongToRadixString", - "floatToHex", - "doubleToHex", - "printUnsignedBytes", - "base64ToHex", - "hexToBase64", - "base64ToBytes", - "base64ToBytesList", - "bytesToBase64", - "bytesToHex", - "toFlatMap", - "encodeURI", - "decodeURI", - "raiseError", - "isBinary", - "isOctal", - "isDecimal", - "isHexadecimal", - "bytesToExecutionArrayList", - "padStart", - "padEnd", - "parseByteToBinaryArray", - "parseBytesToBinaryArray", - "parseLongToBinaryArray", - "parseBinaryArrayToInt", - "isNaN", -]; +export const tbelUtilsAutocompletes = new TbEditorCompleter(tbelEditorCompletions); + +const tbelUtilsFuncNames = Object.keys(tbelEditorCompletions); export const tbelUtilsFuncHighlightRules: Array = tbelUtilsFuncNames.map(funcName => ({ From 76c400f5f4ee771a387245d3327a471d08723fd3 Mon Sep 17 00:00:00 2001 From: Ekaterina Chantsova Date: Fri, 14 Mar 2025 12:11:31 +0200 Subject: [PATCH 090/116] Added link to help page for timewindow settings --- .../components/time/timewindow-config-dialog.component.html | 2 +- ui-ngx/src/app/shared/models/constants.ts | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html index 2b746e4d25..09bc049d32 100644 --- a/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html +++ b/ui-ngx/src/app/shared/components/time/timewindow-config-dialog.component.html @@ -19,7 +19,7 @@

{{ 'timewindow.timewindow-settings' | translate }}

- +