From 289c5674db59e6e666a90ad4f5aaebc5d1353fcf Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Wed, 17 Dec 2025 17:36:57 +0200 Subject: [PATCH 01/18] Fetch and drop partitioning tables --- .../server/service/ttl/EdgeEventsCleanUpService.java | 1 - .../server/dao/sql/asset/AssetRepository.java | 3 --- .../server/dao/sql/edge/JpaBaseEdgeEventDao.java | 3 --- .../dao/sql/entityview/EntityViewRepository.java | 3 --- .../server/dao/sql/entityview/JpaEntityViewDao.java | 3 --- .../server/dao/sql/relation/JpaRelationDao.java | 11 +++-------- .../server/dao/sql/tenant/TenantRepository.java | 3 --- .../dao/sql/usagerecord/ApiUsageStateRepository.java | 3 --- .../dao/sql/usagerecord/JpaApiUsageStateDao.java | 3 --- .../server/dao/sql/widget/JpaWidgetTypeDao.java | 3 --- .../server/dao/sql/widget/JpaWidgetsBundleDao.java | 3 --- .../dao/sql/widget/WidgetsBundleRepository.java | 4 ---- .../sqlts/insert/sql/SqlPartitioningRepository.java | 5 +++-- dao/src/main/resources/sql/schema-ts-psql.sql | 8 ++++---- 14 files changed, 10 insertions(+), 46 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java index 8b38ca32bb..dfa8f36a3e 100644 --- a/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java +++ b/application/src/main/java/org/thingsboard/server/service/ttl/EdgeEventsCleanUpService.java @@ -20,7 +20,6 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; -import org.thingsboard.server.dao.edge.EdgeEventDao; import org.thingsboard.server.dao.edge.EdgeEventService; import org.thingsboard.server.dao.sqlts.insert.sql.SqlPartitioningRepository; import org.thingsboard.server.queue.discovery.PartitionService; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java index e475864684..be36ce7dd1 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/asset/AssetRepository.java @@ -30,9 +30,6 @@ import org.thingsboard.server.dao.model.sql.AssetInfoEntity; import java.util.List; import java.util.UUID; -/** - * Created by Valerii Sosliuk on 5/21/2017. - */ public interface AssetRepository extends JpaRepository, ExportableEntityRepository { @Query("SELECT new org.thingsboard.server.dao.model.sql.AssetInfoEntity(a, c.title, c.additionalInfo, p.name) " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java index ea2abbba8a..e30946f744 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/edge/JpaBaseEdgeEventDao.java @@ -86,9 +86,6 @@ public class JpaBaseEdgeEventDao extends JpaPartitionedAbstractDao queue; diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java index 6094e9b171..b460699b22 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/EntityViewRepository.java @@ -29,9 +29,6 @@ import org.thingsboard.server.dao.model.sql.EntityViewInfoEntity; import java.util.List; import java.util.UUID; -/** - * Created by Victor Basanets on 8/31/2017. - */ public interface EntityViewRepository extends JpaRepository, ExportableEntityRepository { @Query("SELECT new org.thingsboard.server.dao.model.sql.EntityViewInfoEntity(e, c.title, c.additionalInfo) " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java index 44d8a09ff4..dd9f302588 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/entityview/JpaEntityViewDao.java @@ -44,9 +44,6 @@ import java.util.UUID; import static org.thingsboard.server.dao.DaoUtil.convertTenantEntityTypesToDto; -/** - * Created by Victor Basanets on 8/31/2017. - */ @Component @Slf4j @SqlDao diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java index 7417418f54..3d9115dda0 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/relation/JpaRelationDao.java @@ -49,9 +49,6 @@ import static org.thingsboard.server.dao.model.ModelConstants.RELATION_TYPE_GROU import static org.thingsboard.server.dao.model.ModelConstants.RELATION_TYPE_PROPERTY; import static org.thingsboard.server.dao.model.ModelConstants.VERSION_COLUMN; -/** - * Created by Valerii Sosliuk on 5/29/2017. - */ @Slf4j @Component @SqlDao @@ -256,9 +253,7 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple if (!CollectionUtils.isEmpty(relationTypeGroups)) { sqlBuilder.append("AND relation_type_group IN (?"); - for (int i = 1; i < relationTypeGroups.size(); i++) { - sqlBuilder.append(", ?"); - } + sqlBuilder.append(", ?".repeat(Math.max(0, relationTypeGroups.size() - 1))); sqlBuilder.append(")"); params.addAll(relationTypeGroups); } @@ -285,12 +280,12 @@ public class JpaRelationDao extends JpaAbstractDaoListeningExecutorService imple relation.setTypeGroup(RelationTypeGroup.valueOf((String) relationTypeGroup)); relation.setVersion((Long) version); return relation; - }) - .collect(Collectors.toList()); + }).toList(); } @Override public List findRuleNodeToRuleChainRelations(RuleChainType ruleChainType, int limit) { return DaoUtil.convertDataList(relationRepository.findRuleNodeToRuleChainRelations(ruleChainType, PageRequest.of(0, limit))); } + } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java index 08859d5f63..f424afaf39 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/tenant/TenantRepository.java @@ -28,9 +28,6 @@ import org.thingsboard.server.dao.model.sql.TenantInfoEntity; import java.util.List; import java.util.UUID; -/** - * Created by Valerii Sosliuk on 4/30/2017. - */ public interface TenantRepository extends JpaRepository { @Query("SELECT new org.thingsboard.server.dao.model.sql.TenantInfoEntity(t, p.name) " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/ApiUsageStateRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/ApiUsageStateRepository.java index 98e62fc110..b3afa997c9 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/ApiUsageStateRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/ApiUsageStateRepository.java @@ -29,9 +29,6 @@ import org.thingsboard.server.dao.model.sql.ApiUsageStateEntity; import java.util.List; import java.util.UUID; -/** - * @author Valerii Sosliuk - */ public interface ApiUsageStateRepository extends JpaRepository { @Query("SELECT ur FROM ApiUsageStateEntity ur WHERE ur.tenantId = :tenantId " + diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java index ec68fa34c3..83f9c0693c 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/usagerecord/JpaApiUsageStateDao.java @@ -34,9 +34,6 @@ import org.thingsboard.server.dao.util.SqlDao; import java.util.List; import java.util.UUID; -/** - * @author Andrii Shvaika - */ @Component @SqlDao public class JpaApiUsageStateDao extends JpaAbstractDao implements ApiUsageStateDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java index 18fb544dcb..900e508736 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetTypeDao.java @@ -53,9 +53,6 @@ import java.util.stream.Collectors; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; -/** - * Created by Valerii Sosliuk on 4/29/2017. - */ @Component @SqlDao public class JpaWidgetTypeDao extends JpaAbstractDao implements WidgetTypeDao, TenantEntityDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java index bc81be054a..d3f5e9c208 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/JpaWidgetsBundleDao.java @@ -42,9 +42,6 @@ import java.util.UUID; import static org.thingsboard.server.dao.model.ModelConstants.NULL_UUID; -/** - * Created by Valerii Sosliuk on 4/23/2017. - */ @Component @SqlDao public class JpaWidgetsBundleDao extends JpaAbstractDao implements WidgetsBundleDao, TenantEntityDao { diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java index de778588dd..3033154484 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/widget/WidgetsBundleRepository.java @@ -21,7 +21,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; -import org.thingsboard.server.common.data.edqs.fields.WidgetTypeFields; import org.thingsboard.server.common.data.edqs.fields.WidgetsBundleFields; import org.thingsboard.server.dao.ExportableEntityRepository; import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity; @@ -29,9 +28,6 @@ import org.thingsboard.server.dao.model.sql.WidgetsBundleEntity; import java.util.List; import java.util.UUID; -/** - * Created by Valerii Sosliuk on 4/23/2017. - */ public interface WidgetsBundleRepository extends JpaRepository, ExportableEntityRepository { WidgetsBundleEntity findWidgetsBundleByTenantIdAndAlias(UUID tenantId, String alias); diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java index f9b0be2395..55ecb9269d 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java @@ -41,7 +41,7 @@ public class SqlPartitioningRepository { @Autowired private JdbcTemplate jdbcTemplate; - private static final String SELECT_PARTITIONS_STMT = "SELECT tablename from pg_tables WHERE schemaname = 'public' and tablename like concat(?, '_%')"; + private static final String SELECT_PARTITIONS_STMT = "SELECT tablename from pg_tables WHERE schemaname = current_schema() and tablename like concat(?, '_%')"; private static final int PSQL_VERSION_14 = 140000; private volatile Integer currentServerVersion; @@ -54,7 +54,8 @@ public class SqlPartitioningRepository { getJdbcTemplate().execute(partition.getQuery()); } - @Transactional(propagation = Propagation.NOT_SUPPORTED) // executing non-transactionally, so that parent transaction is not aborted on partition save error + @Transactional(propagation = Propagation.NOT_SUPPORTED) + // executing non-transactionally, so that parent transaction is not aborted on partition save error public void createPartitionIfNotExists(String table, long entityTs, long partitionDurationMs) { long partitionStartTs = calculatePartitionStartTime(entityTs, partitionDurationMs); Map partitions = tablesPartitions.computeIfAbsent(table, t -> new ConcurrentHashMap<>()); diff --git a/dao/src/main/resources/sql/schema-ts-psql.sql b/dao/src/main/resources/sql/schema-ts-psql.sql index 1c88ca5604..08dfa315c9 100644 --- a/dao/src/main/resources/sql/schema-ts-psql.sql +++ b/dao/src/main/resources/sql/schema-ts-psql.sql @@ -72,7 +72,7 @@ BEGIN IF partition_type = 'YEARS' THEN FOR partition IN SELECT tablename FROM pg_tables - WHERE schemaname = 'public' + WHERE schemaname = current_schema() AND tablename like 'ts_kv_' || '%' AND tablename != 'ts_kv_latest' AND tablename != 'key_dictionary' @@ -93,7 +93,7 @@ BEGIN ELSE FOR partition IN SELECT tablename FROM pg_tables - WHERE schemaname = 'public' + WHERE schemaname = current_schema() AND tablename like 'ts_kv_' || '%' AND tablename != 'ts_kv_latest' AND tablename != 'key_dictionary' @@ -135,7 +135,7 @@ BEGIN ELSE FOR partition IN SELECT tablename FROM pg_tables - WHERE schemaname = 'public' + WHERE schemaname = current_schema() AND tablename like 'ts_kv_' || '%' AND tablename != 'ts_kv_latest' AND tablename != 'key_dictionary' @@ -205,7 +205,7 @@ BEGIN IF partition IS NOT NULL THEN IF NOT EXISTS(SELECT FROM pg_tables - WHERE schemaname = 'public' + WHERE schemaname = current_schema() AND tablename = partition) THEN partition := NULL; RAISE NOTICE 'Failed to found partition by ttl'; From 9684a1e8ad16300de6cbcf40348179cb57f139a1 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Wed, 17 Dec 2025 17:42:32 +0200 Subject: [PATCH 02/18] Revert --- .../server/dao/sqlts/insert/sql/SqlPartitioningRepository.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java index 55ecb9269d..0a7cf237c8 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java @@ -54,8 +54,7 @@ public class SqlPartitioningRepository { getJdbcTemplate().execute(partition.getQuery()); } - @Transactional(propagation = Propagation.NOT_SUPPORTED) - // executing non-transactionally, so that parent transaction is not aborted on partition save error + @Transactional(propagation = Propagation.NOT_SUPPORTED)// executing non-transactionally, so that parent transaction is not aborted on partition save error public void createPartitionIfNotExists(String table, long entityTs, long partitionDurationMs) { long partitionStartTs = calculatePartitionStartTime(entityTs, partitionDurationMs); Map partitions = tablesPartitions.computeIfAbsent(table, t -> new ConcurrentHashMap<>()); From 1baaed8279c5dcd29ceed94fe3ad262cadbfc741 Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Wed, 17 Dec 2025 17:51:09 +0200 Subject: [PATCH 03/18] Improve EventsDeletionTaskProcessor to delete only non-debug types --- .../EventsDeletionTaskProcessor.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java index cd3953130f..8a0a1c882f 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java @@ -17,6 +17,11 @@ package org.thingsboard.server.service.housekeeper.processor; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; +import org.thingsboard.server.common.data.event.ErrorEventFilter; +import org.thingsboard.server.common.data.event.EventFilter; +import org.thingsboard.server.common.data.event.EventType; +import org.thingsboard.server.common.data.event.LifeCycleEventFilter; +import org.thingsboard.server.common.data.event.StatisticsEventFilter; import org.thingsboard.server.common.data.housekeeper.HousekeeperTask; import org.thingsboard.server.common.data.housekeeper.HousekeeperTaskType; import org.thingsboard.server.dao.event.EventService; @@ -29,7 +34,22 @@ public class EventsDeletionTaskProcessor extends HousekeeperTaskProcessor new ErrorEventFilter(); + case LC_EVENT -> new LifeCycleEventFilter(); + case STATS -> new StatisticsEventFilter(); + default -> throw new IllegalArgumentException("Unexpected non-debug event type: " + eventType); + }; } @Override From 6e6addaf9520a19dbb7b9747548085e46dd8bbd4 Mon Sep 17 00:00:00 2001 From: dashevchenko Date: Wed, 24 Dec 2025 15:52:21 +0200 Subject: [PATCH 04/18] extended getTenantsByIds API for tenant admins --- .../server/controller/TenantController.java | 15 +++++++++++++-- .../server/controller/TenantControllerTest.java | 5 +++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/controller/TenantController.java b/application/src/main/java/org/thingsboard/server/controller/TenantController.java index 2071918dc1..f278f4fd18 100644 --- a/application/src/main/java/org/thingsboard/server/controller/TenantController.java +++ b/application/src/main/java/org/thingsboard/server/controller/TenantController.java @@ -169,7 +169,7 @@ public class TenantController extends BaseController { return checkNotNull(tenantService.findTenantInfos(pageLink)); } - @PreAuthorize("hasAnyAuthority('SYS_ADMIN')") + @PreAuthorize("hasAnyAuthority('SYS_ADMIN', 'TENANT_ADMIN')") @GetMapping(value = "/tenants", params = {"tenantIds"}) public List getTenantsByIds( @Parameter(description = "A list of tenant ids, separated by comma ','", array = @ArraySchema(schema = @Schema(type = "string"))) @@ -179,7 +179,18 @@ public class TenantController extends BaseController { for (UUID tenantIdUUID : tenantUUIDs) { tenantIds.add(TenantId.fromUUID(tenantIdUUID)); } - return tenantService.findTenantsByIds(tenantId, tenantIds); + List tenants = tenantService.findTenantsByIds(tenantId, tenantIds); + return filterTenantsByReadPermission(tenants); + } + + private List filterTenantsByReadPermission(List tenants) { + return tenants.stream().filter(tenant -> { + try { + return accessControlService.hasPermission(getCurrentUser(), Resource.TENANT, Operation.READ, tenant.getId(), tenant); + } catch (ThingsboardException e) { + return false; + } + }).toList(); } } diff --git a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java index 4b439ab4f9..1c0776c2ce 100644 --- a/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java +++ b/application/src/test/java/org/thingsboard/server/controller/TenantControllerTest.java @@ -219,6 +219,11 @@ public class TenantControllerTest extends AbstractControllerTest { Assert.assertEquals(savedTenant, foundTenant); } + loginTenantAdmin(); + Tenant[] foundTenantsByTenant = doGet("/api/tenants?tenantIds=" + idsParam, Tenant[].class); + assertThat(foundTenantsByTenant).isEmpty(); + + loginSysAdmin(); for (Tenant savedTenant : savedTenants) { deleteTenant(savedTenant.getId()); } From c4de8926e40779b6ce39413f22c53f4dc6e190ef Mon Sep 17 00:00:00 2001 From: Andrii Landiak Date: Wed, 7 Jan 2026 12:34:25 +0200 Subject: [PATCH 05/18] Refactoring after review --- .../EventsDeletionTaskProcessor.java | 23 ++----- .../server/dao/event/EventService.java | 2 + .../server/dao/event/BaseEventService.java | 12 ++-- .../server/dao/event/EventDao.java | 60 +------------------ .../server/dao/sql/event/JpaBaseEventDao.java | 8 ++- .../insert/sql/SqlPartitioningRepository.java | 2 +- 6 files changed, 22 insertions(+), 85 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java b/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java index 8a0a1c882f..738249f29c 100644 --- a/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java +++ b/application/src/main/java/org/thingsboard/server/service/housekeeper/processor/EventsDeletionTaskProcessor.java @@ -17,15 +17,13 @@ package org.thingsboard.server.service.housekeeper.processor; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; -import org.thingsboard.server.common.data.event.ErrorEventFilter; -import org.thingsboard.server.common.data.event.EventFilter; import org.thingsboard.server.common.data.event.EventType; -import org.thingsboard.server.common.data.event.LifeCycleEventFilter; -import org.thingsboard.server.common.data.event.StatisticsEventFilter; import org.thingsboard.server.common.data.housekeeper.HousekeeperTask; import org.thingsboard.server.common.data.housekeeper.HousekeeperTaskType; import org.thingsboard.server.dao.event.EventService; +import java.util.Arrays; + @Component @RequiredArgsConstructor public class EventsDeletionTaskProcessor extends HousekeeperTaskProcessor { @@ -35,21 +33,8 @@ public class EventsDeletionTaskProcessor extends HousekeeperTaskProcessor new ErrorEventFilter(); - case LC_EVENT -> new LifeCycleEventFilter(); - case STATS -> new StatisticsEventFilter(); - default -> throw new IllegalArgumentException("Unexpected non-debug event type: " + eventType); - }; + EventType[] nonDebugEventTypes = Arrays.stream(EventType.values()).filter(eventType -> !eventType.isDebug()).toArray(EventType[]::new); + eventService.removeEvents(task.getTenantId(), task.getEntityId(), 0L, System.currentTimeMillis(), nonDebugEventTypes); } @Override diff --git a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java index 556ef0371d..26223f14e2 100644 --- a/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java +++ b/common/dao-api/src/main/java/org/thingsboard/server/dao/event/EventService.java @@ -41,6 +41,8 @@ public interface EventService { void removeEvents(TenantId tenantId, EntityId entityId); + void removeEvents(TenantId tenantId, EntityId entityId, Long startTime, Long endTime, EventType... types); + void removeEvents(TenantId tenantId, EntityId entityId, EventFilter eventFilter, Long startTime, Long endTime); void cleanupEvents(long regularEventExpTs, long debugEventExpTs, boolean cleanupDb); diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java index d81d8eb0f3..68ffce0acf 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/BaseEventService.java @@ -47,11 +47,6 @@ import java.util.stream.Collectors; @Slf4j public class BaseEventService implements EventService { - @Value("${sql.ttl.events.events_ttl:0}") - private long ttlInSec; - @Value("${sql.ttl.events.debug_events_ttl:604800}") - private long debugTtlInSec; - @Value("${event.debug.max-symbols:4096}") private int maxDebugEventSymbols; @@ -125,7 +120,12 @@ public class BaseEventService implements EventService { @Override public void removeEvents(TenantId tenantId, EntityId entityId) { - removeEvents(tenantId, entityId, null, null, null); + removeEvents(tenantId, entityId, null, null); + } + + @Override + public void removeEvents(TenantId tenantId, EntityId entityId, Long startTime, Long endTime, EventType... types) { + eventDao.removeEvents(tenantId.getId(), entityId.getId(), startTime, endTime, types); } @Override diff --git a/dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java b/dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java index 7494ad2532..d8c7a0678a 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/event/EventDao.java @@ -25,80 +25,24 @@ import org.thingsboard.server.common.data.page.TimePageLink; import java.util.List; import java.util.UUID; -/** - * The Interface EventDao. - */ public interface EventDao { - /** - * Save or update event object async - * - * @param event the event object - * @return saved event object future - */ ListenableFuture saveAsync(Event event); - /** - * Find events by tenantId, entityId, eventType and pageLink. - * - * @param tenantId the tenantId - * @param entityId the entityId - * @param eventType the eventType - * @param pageLink the pageLink - * @return the event list - */ PageData findEvents(UUID tenantId, UUID entityId, EventType eventType, TimePageLink pageLink); PageData findEventByFilter(UUID tenantId, UUID entityId, EventFilter eventFilter, TimePageLink pageLink); - /** - * Find latest events by tenantId, entityId and eventType. - * - * @param tenantId the tenantId - * @param entityId the entityId - * @param eventType the eventType - * @param limit the limit - * @return the event list - */ List findLatestEvents(UUID tenantId, UUID entityId, EventType eventType, int limit); - /** - * Find latest debug IN event by tenantId, entityId. - * - * @param tenantId the tenantId - * @param entityId the entityId - * @return the latest debug IN event - */ Event findLatestDebugRuleNodeInEvent(UUID tenantId, UUID entityId); - /** - * Executes stored procedure to cleanup old events. Uses separate ttl for debug and other events. - * @param regularEventExpTs the expiration time of the regular events - * @param debugEventExpTs the expiration time of the debug events - * @param cleanupDb - */ void cleanupEvents(long regularEventExpTs, long debugEventExpTs, boolean cleanupDb); - /** - * Removes all events for the specified entity and time interval - * - * @param tenantId - * @param entityId - * @param startTime - * @param endTime - */ void removeEvents(UUID tenantId, UUID entityId, Long startTime, Long endTime); - /** - * - * Removes all events for the specified entity, event filter and time interval - * - * @param tenantId - * @param entityId - * @param eventFilter - * @param startTime - * @param endTime - */ + void removeEvents(UUID tenantId, UUID entityId, Long startTime, Long endTime, EventType... types); + void removeEvents(UUID tenantId, UUID entityId, EventFilter eventFilter, Long startTime, Long endTime); } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java index 189e024608..5cd9012831 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sql/event/JpaBaseEventDao.java @@ -173,8 +173,14 @@ public class JpaBaseEventDao implements EventDao { @Override public void removeEvents(UUID tenantId, UUID entityId, Long startTime, Long endTime) { + removeEvents(tenantId, entityId, startTime, endTime, EventType.values()); + } + + @Override + public void removeEvents(UUID tenantId, UUID entityId, Long startTime, Long endTime, EventType... types) { log.debug("[{}][{}] Remove events [{}-{}] ", tenantId, entityId, startTime, endTime); - for (EventType eventType : EventType.values()) { + EventType[] eventTypes = (types == null || types.length == 0) ? EventType.values() : types; + for (EventType eventType : eventTypes) { getEventRepository(eventType).removeEvents(tenantId, entityId, startTime, endTime); } } diff --git a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java index 0a7cf237c8..550922bbc6 100644 --- a/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java +++ b/dao/src/main/java/org/thingsboard/server/dao/sqlts/insert/sql/SqlPartitioningRepository.java @@ -54,7 +54,7 @@ public class SqlPartitioningRepository { getJdbcTemplate().execute(partition.getQuery()); } - @Transactional(propagation = Propagation.NOT_SUPPORTED)// executing non-transactionally, so that parent transaction is not aborted on partition save error + @Transactional(propagation = Propagation.NOT_SUPPORTED) // executing non-transactionally, so that parent transaction is not aborted on partition save error public void createPartitionIfNotExists(String table, long entityTs, long partitionDurationMs) { long partitionStartTs = calculatePartitionStartTime(entityTs, partitionDurationMs); Map partitions = tablesPartitions.computeIfAbsent(table, t -> new ConcurrentHashMap<>()); From ff6fc12b32c7c5cc5f2c025054f42e558e023d92 Mon Sep 17 00:00:00 2001 From: IrynaMatveieva Date: Wed, 7 Jan 2026 15:32:43 +0200 Subject: [PATCH 06/18] share current timestamp across metrics during cf calculation --- .../EntityAggregationCalculatedFieldState.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/single/EntityAggregationCalculatedFieldState.java b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/single/EntityAggregationCalculatedFieldState.java index 99bddc374c..bb2dd9d0cd 100644 --- a/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/single/EntityAggregationCalculatedFieldState.java +++ b/application/src/main/java/org/thingsboard/server/service/cf/ctx/state/aggregation/single/EntityAggregationCalculatedFieldState.java @@ -68,6 +68,8 @@ public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldSt private CalculatedFieldProcessingService cfProcessingService; + private long now; + public EntityAggregationCalculatedFieldState(EntityId entityId) { super(entityId); } @@ -100,7 +102,7 @@ public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldSt @Override public ListenableFuture performCalculation(Map updatedArgs, CalculatedFieldCtx ctx) throws Exception { createIntervalIfNotExist(); - long now = System.currentTimeMillis(); + now = System.currentTimeMillis(); if (DebugModeUtil.isDebugFailuresAvailable(ctx.getCalculatedField())) { if (debugTracker == null) { @@ -114,7 +116,7 @@ public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldSt Map> results = new HashMap<>(); List expiredIntervals = new ArrayList<>(); getIntervals().forEach((intervalEntry, argIntervalStatuses) -> { - processInterval(now, intervalEntry, argIntervalStatuses, expiredIntervals, results); + processInterval(intervalEntry, argIntervalStatuses, expiredIntervals, results); }); removeExpiredIntervals(expiredIntervals); @@ -202,8 +204,7 @@ public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldSt return intervals; } - private void processInterval(long now, - AggIntervalEntry intervalEntry, + private void processInterval(AggIntervalEntry intervalEntry, Map args, List expiredIntervals, Map> results) { @@ -244,11 +245,11 @@ public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldSt args.forEach((argName, argEntryIntervalStatus) -> { if (argEntryIntervalStatus.intervalPassed(cfCheckInterval)) { if (argEntryIntervalStatus.argsUpdated()) { - argEntryIntervalStatus.setLastMetricsEvalTs(System.currentTimeMillis()); + argEntryIntervalStatus.setLastMetricsEvalTs(now); argEntryIntervalStatus.setLastArgsRefreshTs(DEFAULT_LAST_UPDATE_TS); processArgument(intervalEntry, argName, false, results); } else if (argEntryIntervalStatus.getLastMetricsEvalTs() == DEFAULT_LAST_UPDATE_TS) { - argEntryIntervalStatus.setLastMetricsEvalTs(System.currentTimeMillis()); + argEntryIntervalStatus.setLastMetricsEvalTs(now); processArgument(intervalEntry, argName, true, results); } } From d6a9f8fd2758df8c33eb212c22b77682cd24efed Mon Sep 17 00:00:00 2001 From: Maksym Tsymbarov Date: Wed, 7 Jan 2026 15:48:52 +0200 Subject: [PATCH 07/18] Enhanced validation --- .../home/components/widget/lib/chart/time-series-chart.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts index b1928157e2..21f5f2d68c 100644 --- a/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts +++ b/ui-ngx/src/app/modules/home/components/widget/lib/chart/time-series-chart.ts @@ -661,7 +661,7 @@ export class TbTimeSeriesChart { } } } else if (limit.type === ValueSourceType.constant) { - const value = unitConvertor ? unitConvertor(limit.value) : limit.value; + const value = unitConvertor && isDefinedAndNotNull(limit.value) ? unitConvertor(limit.value) : limit.value; if (limitType === 'min') { yAxis.option.min = value; } else { From 2e1130d80377cb843dc471bcd9bedf673e2459bc Mon Sep 17 00:00:00 2001 From: ArtemDzhereleiko Date: Wed, 7 Jan 2026 15:57:59 +0200 Subject: [PATCH 08/18] UI: Fixed cf and alarm rule in preview --- .../alarm-rules/alarm-rules.component.html | 19 +++++++++++-------- .../alarm-rules/alarm-rules.component.ts | 5 +++-- ...alarm-rule-condition-dialog.component.html | 11 ++++++----- ...f-alarm-rule-condition-dialog.component.ts | 4 ++++ .../cf-alarm-schedule.component.html | 6 +++--- .../create-cf-alarm-rules.component.html | 2 +- ...lex-filter-predicate-dialog.component.html | 12 +++++++----- ...mplex-filter-predicate-dialog.component.ts | 7 +++++++ .../alarm-rule-filter-dialog.component.html | 14 ++++++++------ .../alarm-rule-filter-dialog.component.ts | 7 +++++++ .../alarm-rule-filter-list.component.html | 9 +++++---- .../alarm-rule-filter-list.component.ts | 12 ++++++++---- ...-rule-filter-predicate-list.component.html | 2 +- ...rm-rule-filter-predicate-list.component.ts | 5 ++++- ...ter-predicate-no-data-value.component.html | 4 ++-- ...rule-filter-predicate-value.component.html | 4 ++-- ...alarm-rule-filter-predicate.component.html | 4 ++-- .../alarm-rule-filter-predicate.component.ts | 1 + .../calculated-field.component.html | 5 +++++ ...lated-field-arguments-table.component.html | 2 +- ...culated-field-arguments-table.component.ts | 1 + ...ntity-aggregation-component.component.html | 1 + .../entity-aggregation-component.component.ts | 4 +++- ...eofencing-zone-groups-table.component.html | 2 +- ...-geofencing-zone-groups-table.component.ts | 2 ++ .../geofencing-configuration.component.html | 1 + .../geofencing-configuration.component.ts | 4 +++- .../propagation-configuration.component.html | 1 + .../propagation-configuration.component.ts | 4 +++- ...ities-aggregation-component.component.html | 1 + ...ntities-aggregation-component.component.ts | 4 +++- .../simple-configuration.component.html | 1 + .../simple-configuration.component.ts | 4 +++- .../home/pages/alarm/alarm-routing.module.ts | 3 --- 34 files changed, 112 insertions(+), 56 deletions(-) diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html b/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html index 32107f6eda..b7c30cc9df 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.html @@ -79,6 +79,7 @@ [entityId]="entityId" [tenantId]="tenantId" [ownerId]="ownerId" + [isEditValue]="isEditValue" [watchKeyChange]="true" [entityName]="entityName"/> @@ -97,14 +98,16 @@ - + @if (isEditValue) { + + }
alarm-rule.no-clear-alarm-rule diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts b/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts index 0092bf2132..5ca7b36165 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/alarm-rules.component.ts @@ -53,7 +53,7 @@ import { EntityService } from '@core/http/entity.service'; @Component({ selector: 'tb-alarm-rules', templateUrl: './alarm-rules.component.html', - styleUrls: [] + styleUrls: ['./alarm-rule-dialog.component.scss'] }) export class AlarmRulesComponent extends EntityComponent { @@ -175,7 +175,8 @@ export class AlarmRulesComponent extends EntityComponent
@@ -75,7 +76,7 @@ matTooltip="{{ 'calculated-fields.test-script-function' | translate }}" matTooltipPosition="above" class="tb-mat-32" - [disabled]="!argumentsList.length" + [disabled]="!argumentsList.length || readonly" (click)="onTestScript($event)"> bug_report @@ -84,7 +85,7 @@ @@ -111,7 +112,7 @@ required> } @else { - {{ 'alarm-rule.no-filter-preview' | translate }} + {{ 'alarm-rule.no-filter-preview' | translate }} } @@ -135,7 +136,7 @@ {{ 'alarm-rule.condition-type-hint' | translate }} } - @if (conditionFormGroup.get('type').value == AlarmConditionType.DURATION) { + @if (conditionFormGroup.get('type').value === AlarmConditionType.DURATION) {
{{ 'alarm-rule.value' | translate }}
@@ -167,7 +168,7 @@
- } @else if (conditionFormGroup.get('type').value == AlarmConditionType.REPEATING) { + } @else if (conditionFormGroup.get('type').value === AlarmConditionType.REPEATING) {
{{ 'alarm-rule.value' | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts index 6f691ecd21..05bf08880f 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/cf-alarm-rule-condition-dialog.component.ts @@ -196,6 +196,10 @@ export class CfAlarmRuleConditionDialogComponent extends DialogComponent -
@@ -63,7 +63,7 @@
-
+
@@ -90,7 +90,7 @@
-
diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/create-cf-alarm-rules.component.html b/ui-ngx/src/app/modules/home/components/alarm-rules/create-cf-alarm-rules.component.html index b0ea9f406e..122c52b08f 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/create-cf-alarm-rules.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/create-cf-alarm-rules.component.html @@ -49,7 +49,7 @@
} @if (!createAlarmRulesFormArray().controls.length) { - + alarm-rule.add-create-alarm-rule-prompt } diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html index c0c5a72d77..9fec85d745 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.html @@ -52,10 +52,12 @@ cdkFocusInitial> {{'action.cancel' | translate }} - + @if (!readonly) { + + } diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts index 403a0be8ca..70fed16663 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-complex-filter-predicate-dialog.component.ts @@ -36,6 +36,7 @@ export interface AlarmRuleComplexFilterPredicateDialogData { valueType: EntityKeyValueType; arguments: Record; argumentInUse: string; + readonly: boolean; } @Component({ @@ -63,6 +64,8 @@ export class AlarmRuleComplexFilterPredicateDialogComponent extends arguments = this.data.arguments; + readonly = this.data.readonly; + constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: AlarmRuleComplexFilterPredicateDialogData, @@ -73,6 +76,10 @@ export class AlarmRuleComplexFilterPredicateDialogComponent extends this.isAdd = this.data.isAdd; this.complexFilterFormGroup.patchValue(this.data.complexPredicate, {emitEvent: false}); + + if (this.readonly) { + this.complexFilterFormGroup.disable({emitEvent: false}); + } } cancel(): void { diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.html b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.html index 800e78c9d3..081ce44e88 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.html +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.html @@ -46,7 +46,7 @@ } - + filter.value-type.value-type @@ -93,10 +93,12 @@ cdkFocusInitial> {{ 'action.cancel' | translate }} - + @if (!readonly) { + + } diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.ts b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.ts index fbd19a7a47..312954aa5a 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-dialog.component.ts @@ -39,6 +39,7 @@ isAdd: boolean; arguments: Record; usedArguments: Array; + readonly: boolean; } @Component({ @@ -66,6 +67,8 @@ export class AlarmRuleFilterDialogComponent extends DialogComponent; + readonly = this.data.readonly; + constructor(protected store: Store, protected router: Router, @Inject(MAT_DIALOG_DATA) public data: AlarmRuleFilterDialogData, @@ -114,6 +117,10 @@ export class AlarmRuleFilterDialogComponent extends DialogComponent
-
{{ filterControl.value?.argument }}
-
{{ FilterPredicateTypeTranslationMap.get(filterControl.value?.valueType) | translate }}
+
{{ filterControl.value?.argument }}
+
{{ FilterPredicateTypeTranslationMap.get(filterControl.value?.valueType) | translate }}
diff --git a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.ts b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.ts index 647d294268..c2a5601739 100644 --- a/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.ts +++ b/ui-ngx/src/app/modules/home/components/alarm-rules/filter/alarm-rule-filter-predicate.component.ts @@ -203,6 +203,7 @@ export class AlarmRuleFilterPredicateComponent implements ControlValueAccessor, isAdd: false, arguments: this.arguments, argumentInUse: this.argumentInUse, + readonly: this.disabled } }).afterClosed().subscribe( (result) => { diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.html index 1150b5b2a6..6e2297b958 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/calculated-field.component.html @@ -101,6 +101,7 @@ [entityName]="entityName" [ownerId]="ownerId" [tenantId]="tenantId" + [isEditValue]="isEditValue" > } @case (CalculatedFieldType.PROPAGATION) { @@ -111,6 +112,7 @@ [tenantId]="tenantId" [ownerId]="ownerId" [testScript]="onTestScript.bind(this)" + [isEditValue]="isEditValue" > } @case (CalculatedFieldType.RELATED_ENTITIES_AGGREGATION) { @@ -120,6 +122,7 @@ [entityName]="entityName" [tenantId]="tenantId" [testScript]="onTestScript.bind(this)" + [isEditValue]="isEditValue" > } @case (CalculatedFieldType.ENTITY_AGGREGATION) { @@ -128,6 +131,7 @@ [entityId]="entityId" [entityName]="entityName" [tenantId]="tenantId" + [isEditValue]="isEditValue" > } @default { @@ -139,6 +143,7 @@ [tenantId]="tenantId" [isScript]="entityForm.get('type').value === CalculatedFieldType.SCRIPT" [testScript]="onTestScript.bind(this)" + [isEditValue]="isEditValue" > } } diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/calculated-field-arguments/calculated-field-arguments-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/calculated-field-arguments/calculated-field-arguments-table.component.html index c61ce4c467..e3eb3f524c 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/calculated-field-arguments/calculated-field-arguments-table.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/calculated-field-arguments/calculated-field-arguments-table.component.html @@ -93,7 +93,7 @@
- @if (disable) { + @if (!isEditValue) {
diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts b/ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts index 6f281b8e25..d7312db7a1 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/entity-aggregation-configuration/entity-aggregation-component.component.ts @@ -14,7 +14,7 @@ /// limitations under the License. /// -import { Component, forwardRef, Input } from '@angular/core'; +import { booleanAttribute, Component, forwardRef, Input } from '@angular/core'; import { ControlValueAccessor, FormBuilder, @@ -87,6 +87,8 @@ export class EntityAggregationComponentComponent implements ControlValueAccessor @Input() testScript: (expression?: string) => Observable; + @Input({transform: booleanAttribute}) isEditValue = true; + readonly minAllowedAggregationIntervalInSecForCF = getCurrentAuthState(this.store).minAllowedAggregationIntervalInSecForCF; readonly intermediateAggregationIntervalInSecForCF = getCurrentAuthState(this.store).intermediateAggregationIntervalInSecForCF; readonly DayInSec = DAY / SECOND; diff --git a/ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-table.component.html b/ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-table.component.html index d661f5021a..cf3ba5209e 100644 --- a/ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-table.component.html +++ b/ui-ngx/src/app/modules/home/components/calculated-fields/components/geofencing-configuration/calculated-field-geofencing-zone-groups-table.component.html @@ -96,7 +96,7 @@
- @if (disable) { + @if (!isEditValue) {